版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
1、深入理解Java反射機(jī)制本文較為詳細(xì)的分析了Java反射機(jī)制。分享給大家供大家參考,具體如下: 一、預(yù)先需要掌握的知識(java虛擬機(jī)) java虛擬機(jī)的方法區(qū): java虛擬機(jī)有一個(gè)運(yùn)行時(shí)數(shù)據(jù)區(qū),這個(gè)數(shù)據(jù)區(qū)又被分為方法區(qū),堆區(qū)和棧區(qū),我們這里需要了解的主要是方法區(qū)。方法區(qū)的主要作用是存儲被裝載的類 的類型信息,當(dāng)java虛擬機(jī)裝載某個(gè)類型的時(shí)候,需要類裝載器定位相應(yīng)的class文件,然后將其讀入到j(luò)ava虛擬機(jī)中,緊接著虛擬機(jī)提取class 中的類型信息,將這些信息存儲到方法區(qū)中。這些信息主要包括: 1、這個(gè)類型的全限定名 2、這個(gè)類型的直接超類的全限定名 3、這個(gè)類型是類類型還是接口類型
2、4、這個(gè)類型的訪問修飾符 5、任何直接超接口的全限定名的有序列表 6、該類型的常量池 7、字段信息 8、方法信息 9、除了常量以外的所有類變量 10、一個(gè)到class類的引用 等等(讀者可以參考深入java虛擬機(jī)這本書的敘述) Class類: Class類是一個(gè)非常重要的java基礎(chǔ)類,每當(dāng)裝載一個(gè)新的類型的時(shí)候,java虛擬機(jī)都會在java堆中創(chuàng)建一個(gè)對應(yīng)于新類型的Class實(shí)例,該實(shí)例就代表此類型,通過該Class實(shí)例我們就可以訪問該類型的基本信息。上面說到在方法區(qū)中會存儲某個(gè)被裝載類的類型信息,我們就可以通過 Class實(shí)例來訪問這些信息。比如,對于上面說到的信息Class中都有對應(yīng)的方
3、法,如下: 1、getName();這個(gè)類型的全限定名 2、getSuperClass();這個(gè)類型的直接超類的全限定名 3、isInterface();這個(gè)類型是類類型還是接口類型 4、getTypeParamters();這個(gè)類型的訪問修飾符 5、getInterfaces();任何直接超接口的全限定名的有序列表 6、getFields();字段信息 7、getMethods();方法信息 等等(讀者可以自己參看jdk幫助文檔,得到更多的信息) 二、java反射詳解 反射的概念:所謂的反射就是java語言在運(yùn)行時(shí)擁有一項(xiàng)自觀的能力,反射使您的程序代碼能夠得到裝載到JVM中的類的內(nèi)部信息,允
4、許您執(zhí)行程序時(shí)才得到需要類的內(nèi)部信息,而不是在編寫代碼的時(shí)候就必須要知道所需類的內(nèi)部信息,這使反射成為構(gòu)建靈活的應(yīng)用的主要工具。 反射的常用類和函數(shù):Java反射機(jī)制的實(shí)現(xiàn)要借助于4個(gè)類:Class,Constructor,F(xiàn)ield,Method;其中class代 表的是類對象,Constructor類的構(gòu)造器對象,F(xiàn)ield類的屬性對象,Method類的方法對象,通過這四個(gè)對象我們可以粗略的看到一個(gè)類的各個(gè)組成部分。其中最核心的就是Class類,它是實(shí)現(xiàn)反射的基礎(chǔ),它包含的方法我們在第一部分已經(jīng)進(jìn)行了基本的闡述。應(yīng)用反射時(shí)我們最關(guān)心的一般是一個(gè)類的構(gòu)造器、屬性和方法,下面我們主要介紹Cla
5、ss類中針對這三個(gè)元素的方法: 1、得到構(gòu)造器的方法 Constructor getConstructor(Class params) - 獲得使用特殊的參數(shù)類型的公共構(gòu)造函數(shù), Constructor getConstructors() - 獲得類的所有公共構(gòu)造函數(shù) Constructor getDeclaredConstructor(Class params) - 獲得使用特定參數(shù)類型的構(gòu)造函數(shù)(與接入級別無關(guān)) Constructor getDeclaredConstructors() - 獲得類的所有構(gòu)造函數(shù)(與接入級別無關(guān)) 2、獲得字段信息的方法 Field getField(St
6、ring name) - 獲得命名的公共字段 Field getFields() - 獲得類的所有公共字段 Field getDeclaredField(String name) - 獲得類聲明的命名的字段 Field getDeclaredFields() - 獲得類聲明的所有字段 3、獲得方法信息的方法 Method getMethod(String name, Class params) - 使用特定的參數(shù)類型,獲得命名的公共方法 Method getMethods() - 獲得類的所有公共方法 Method getDeclaredMethod(String name, Class pa
7、rams) - 使用特寫的參數(shù)類型,獲得類聲明的命名的方法 Method getDeclaredMethods() - 獲得類聲明的所有方法 應(yīng)用反射的基本步驟: 1、獲得你想操作的類的Class對象; 方法一:Classc=Class.forName("java.lang.String") /這種方式獲得類的Class對象需要 包名.類名 方法二:對于基本數(shù)據(jù)類型可以用形如Class c=int.class或Class c=Integer.TYPE的語句 方法三:Class c=MyClass.class 2、調(diào)用Class中的方法得到你想得到的信息集合,如調(diào)用getDe
8、claredFields()方法得到類的所有屬性; 3、處理第2步中得到的信息,然后進(jìn)行你想做的實(shí)際操作。 反射實(shí)例: 下面我將針對類的構(gòu)造器、屬性和方法分別舉三個(gè)例子,向大家演示一下反射的應(yīng)用過程。 1、構(gòu)造器 步驟為:通過反射機(jī)制得到某個(gè)類的構(gòu)造器,然后調(diào)用該構(gòu)造器創(chuàng)建該類的一個(gè)實(shí)例import java.lang.reflect.*; public class ConstructorDemo public ConstructorDemo() public ConstructorDemo(int a, int b) System.out.println("a="+a+&
9、quot;b="+b); public static void main(String args) try Class cls =Class.forName("包名.ConstructorDemo"); Class partypes =new Class2; partypes0 = Integer.TYPE; partypes1 =Integer.TYPE; Constructor ct=Constructor(partypes); Object arglist =new Object2; arglist0 = newInteger(37); arglist1 =
10、 newInteger(47); Object retobj = ct.newInstance(arglist); catch (Throwable e) System.err.println(e); 2、屬性 步驟為:通過反射機(jī)制得到某個(gè)類的某個(gè)屬性,然后改變對應(yīng)于這個(gè)類的某個(gè)實(shí)例的該屬性值import java.lang.reflect.*; public class FieldDemo1 public double d; public static void main(String args) try Class cls = Class.forName("FieldDemo1&
11、quot;); Field fld = cls.getField("d"); FieldDemo1 fobj = new FieldDemo1(); System.out.println("d = " + fobj.d); fld.setDouble(fobj, 12.34); System.out.println("d = " + fobj.d); catch (Throwable e) System.err.println(e); 3、方法 步驟為:通過反射機(jī)制得到某個(gè)類的某個(gè)方法,然后調(diào)用對應(yīng)于這個(gè)類的某個(gè)實(shí)例的該方法/通過使用
12、方法的名字調(diào)用方法 import java.lang.reflect.*; public class MethodDemo1 public int add(int a, int b) return a + b; public static void main(String args) try Class cls =Class.forName("MethodDemo1"); Class partypes = new Class2; partypes0 = Integer.TYPE; partypes1 = Integer.TYPE; Method meth = cls.get
13、Method("add",partypes); MethodDemo1 methobj = new MethodDemo1(); Object arglist = new Object2; arglist0 = new Integer(37); arglist1 = new Integer(47); Object retobj= meth.invoke(methobj, arglist); Integer retval = (Integer)retobj; System.out.println(Value(); catch (Throwable e) S
14、println(e); 三、java反射的應(yīng)用(Hibernate) 我們在第二部分中對java反射進(jìn)行了比較系統(tǒng)的闡述,也舉了幾個(gè)簡單的實(shí)例,下面我們就來討論一下java反射的具體應(yīng)用。前面我們已經(jīng)知 道,Java反射機(jī)制提供了一種動(dòng)態(tài)鏈接程序組件的多功能方法,它允許程序創(chuàng)建和控制任何類的對象(根據(jù)安全性限制)之前,無需提前硬編碼目標(biāo)類。這些特 性使得反射特別適用于創(chuàng)建以非常普通的方式與對象協(xié)作的庫。例如,反射經(jīng)常在持續(xù)存儲對象為數(shù)據(jù)庫、XML或其它外部格式的框架中使用。下面我們就已 Hibernate框架為例像大家闡述一下反射的重要意義。 Hibernate是一個(gè)屏蔽了JDBC,實(shí)現(xiàn)了OR
15、M的java框架,利用該框架我們可以拋棄掉繁瑣的sql語句而是利用Hibernate中 Session類的save()方法直接將某個(gè)類的對象存到數(shù)據(jù)庫中,也就是所涉及到sql語句的那些代碼Hibernate幫我們做了。這時(shí)候就出現(xiàn)了 一個(gè)問題,Hibernate怎樣知道他要存的某個(gè)對象都有什么屬性呢?這些屬性都是什么類型呢?如此,它在向數(shù)據(jù)庫中存儲該對象屬性時(shí)的sql語句該怎么構(gòu)造呢?解決這個(gè)問題的利器就是我們的java反射! 下面我們以一個(gè)例子來進(jìn)行闡述,比如我們定義了一個(gè)User類,這個(gè)User類中有20個(gè)屬性和這些屬性的get和set方法,相應(yīng)的在數(shù)據(jù)庫中 有一個(gè)User表,這個(gè)User
16、表中對應(yīng)著20個(gè)字段。假設(shè)我們從User表中提取了一條記錄,現(xiàn)在需要將這條記錄的20個(gè)字段的內(nèi)容分別賦給一個(gè) User對象myUser的20個(gè)屬性,而Hibernate框架在編譯的時(shí)候并不知道這個(gè)User類,他無法直接調(diào)用myUser.getXXX或者 myUser.setXXX方法,此時(shí)就用到了反射,具體處理過程如下: 1、根據(jù)查詢條件構(gòu)造PreparedStament語句,該語句返回20個(gè)字段的值; 2、Hibernate通過讀取配置文件得到User類的屬性列表list(是一個(gè)String數(shù)組)以及這些屬性的類型; 3、創(chuàng)建myUser所屬類的Class對象c;c=myUser.getCl
17、ass(); 4、構(gòu)造一個(gè)for循環(huán),循環(huán)的次數(shù)為list列表的長度; 4.1、讀取listi的值,然后構(gòu)造對應(yīng)該屬性的set方法; 4.2、判斷l(xiāng)isti的類型XXX,調(diào)用PreparedStament語句中的getXXX(i),進(jìn)而得到i出字段的值; 4.3、將4.2中得到的值作為4.1中得到的set方法的參數(shù),這樣就完成了一個(gè)字段像一個(gè)屬性的賦值,如此循環(huán)即可; 看到了吧,這就是反射的功勞,如果沒有反射很難想象如果完成同樣的功能會有多么難!但是反射也有缺點(diǎn),比如性能比較低、安全性比較復(fù)雜等,這里就不在討論這些東西,感興趣的讀者可以在網(wǎng)上找到答案,有很多的!要想理解反射的原理,首先要了解什
18、么是類型信息。Java讓我們在運(yùn)行時(shí)識別對象和類的信息,主要有2種方式:一種是傳統(tǒng)的RTTI,它假定我們在編譯時(shí)已經(jīng)知道了所有的類型信息;另一種是反射機(jī)制,它允許我們在運(yùn)行時(shí)發(fā)現(xiàn)和使用類的信息。1、Class對象理解RTTI在Java中的工作原理,首先需要知道類型信息在運(yùn)行時(shí)是如何表示的,這是由Class對象來完成的,它包含了與類有關(guān)的信息。Class對象就是用來創(chuàng)建所有“常規(guī)”對象的,Java使用Class對象來執(zhí)行RTTI,即使你正在執(zhí)行的是類似類型轉(zhuǎn)換這樣的操作。 每個(gè)類都會產(chǎn)生一個(gè)對應(yīng)的Class對象,也就是保存在.class文件。所有類都是在對其第一次使用時(shí),動(dòng)態(tài)加載到JVM的,當(dāng)程
19、序創(chuàng)建一個(gè)對類的靜態(tài)成員的引用時(shí),就會加載這個(gè)類。Class對象僅在需要的時(shí)候才會加載,static初始化是在類加載時(shí)進(jìn)行的。public class TestMain public static void main(String args) System.out.println(XYZ.name);class XYZ public static String name = "luoxn28"static System.out.println("xyz靜態(tài)塊");public XYZ() System.out.println("xyz構(gòu)造了&q
20、uot;); 輸出結(jié)果為:類加載器首先會檢查這個(gè)類的Class對象是否已被加載過,如果尚未加載,默認(rèn)的類加載器就會根據(jù)類名查找對應(yīng)的.class文件。想在運(yùn)行時(shí)使用類型信息,必須獲取對象(比如類Base對象)的Class對象的引用,使用功能Class.forName(“Base”)可以實(shí)現(xiàn)該目的,或者使用base.class。注意,有一點(diǎn)很有趣,使用功能”.class”來創(chuàng)建Class對象的引用時(shí),不會自動(dòng)初始化該Class對象,使用forName()會自動(dòng)初始化該Class對象。為了使用類而做的準(zhǔn)備工作一般有以下3個(gè)步驟: 加載:由類加載器完成,找到對應(yīng)的字節(jié)碼,創(chuàng)建一個(gè)Class對象 鏈接
21、:驗(yàn)證類中的字節(jié)碼,為靜態(tài)域分配空間 初始化:如果該類有超類,則對其初始化,執(zhí)行靜態(tài)初始化器和靜態(tài)初始化塊public class Base static int num = 1;static System.out.println("Base " + num);public class Main public static void main(String args) / 不會初始化靜態(tài)塊Class clazz1 = Base.class;System.out.println("-");/ 會初始化Class clazz2 = Class.forName
22、("zzz.Base"); 2、類型轉(zhuǎn)換前先做檢查編譯器將檢查類型向下轉(zhuǎn)型是否合法,如果不合法將拋出異常。向下轉(zhuǎn)換類型前,可以使用instanceof判斷。class Base class Derived extends Base public class Main public static void main(String args) Base base = new Derived();if (base instanceof Derived) / 這里可以向下轉(zhuǎn)換了System.out.println("ok");else System.out.pr
23、intln("not ok"); 3、反射:運(yùn)行時(shí)類信息如果不知道某個(gè)對象的確切類型,RTTI可以告訴你,但是有一個(gè)前提:這個(gè)類型在編譯時(shí)必須已知,這樣才能使用RTTI來識別它。Class類與java.lang.reflect類庫一起對反射進(jìn)行了支持,該類庫包含F(xiàn)ield、Method和Constructor類,這些類的對象由JVM在啟動(dòng)時(shí)創(chuàng)建,用以表示未知類里對應(yīng)的成員。這樣的話就可以使用Contructor創(chuàng)建新的對象,用get()和set()方法獲取和修改類中與Field對象關(guān)聯(lián)的字段,用invoke()方法調(diào)用與Method對象關(guān)聯(lián)的方法。另外,還可以調(diào)用getFi
24、elds()、getMethods()和getConstructors()等許多便利的方法,以返回表示字段、方法、以及構(gòu)造器對象的數(shù)組,這樣,對象信息可以在運(yùn)行時(shí)被完全確定下來,而在編譯時(shí)不需要知道關(guān)于類的任何事情。反射機(jī)制并沒有什么神奇之處,當(dāng)通過反射與一個(gè)未知類型的對象打交道時(shí),JVM只是簡單地檢查這個(gè)對象,看它屬于哪個(gè)特定的類。因此,那個(gè)類的.class對于JVM來說必須是可獲取的,要么在本地機(jī)器上,要么從網(wǎng)絡(luò)獲取。所以對于RTTI和反射之間的真正區(qū)別只在于: RTTI,編譯器在編譯時(shí)打開和檢查.class文件 反射,運(yùn)行時(shí)打開和檢查.class文件public class Person
25、 implements Serializable private String name;private int age;/ get/set方法public static void main(String args) Person person = new Person("luoxn28", 23);Class clazz = person.getClass();Field fields = clazz.getDeclaredFields();for (Field field : fields) String key = field.getName();PropertyDe
26、scriptor descriptor = new PropertyDescriptor(key, clazz);Method method = descriptor.getReadMethod();Object value = method.invoke(person);System.out.println(key + ":" + value); 以上通過getReadMethod()方法調(diào)用類的get函數(shù),可以通過getWriteMethod()方法來調(diào)用類的set方法。通常來說,我們不需要使用反射工具,但是它們在創(chuàng)建動(dòng)態(tài)代碼會更有用,反射在Java中用來支持其他特性的
27、,例如對象的序列化和JavaBean等。4、動(dòng)態(tài)代理代理模式是為了提供額外或不同的操作,而插入的用來替代”實(shí)際”對象的對象,這些操作涉及到與”實(shí)際”對象的通信,因此代理通常充當(dāng)中間人角色。Java的動(dòng)態(tài)代理比代理的思想更前進(jìn)了一步,它可以動(dòng)態(tài)地創(chuàng)建并代理并動(dòng)態(tài)地處理對所代理方法的調(diào)用。在動(dòng)態(tài)代理上所做的所有調(diào)用都會被重定向到單一的調(diào)用處理器上,它的工作是揭示調(diào)用的類型并確定相應(yīng)的策略。以下是一個(gè)動(dòng)態(tài)代理示例:接口和實(shí)現(xiàn)類:public interface Interface void doSomething();void somethingElse(String arg);public class RealObject implements Interface public void doSomething() System.out.println("doSomething.");public void somethingElse(String arg) System.out.println
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025年度國畫藝術(shù)產(chǎn)業(yè)投資合同3篇
- 2024版簡單鋼結(jié)構(gòu)合同
- 二零二五年度建筑工程承包合同標(biāo)的和工程量清單2篇
- 2024版智慧城市建設(shè)項(xiàng)目合同
- 2025年度國際環(huán)保技術(shù)引進(jìn)與實(shí)施合同3篇
- 2024影視制作基地建設(shè)與運(yùn)營合同
- 四川文軒職業(yè)學(xué)院《大數(shù)據(jù)處理與Mapeduce編程模型實(shí)踐》2023-2024學(xué)年第一學(xué)期期末試卷
- 二零二五版工業(yè)自動(dòng)化設(shè)備安裝施工合同范本2篇
- 二零二五版?zhèn)€人信用擔(dān)保車輛購置貸款合同樣本3篇
- 2024暑假大學(xué)生創(chuàng)業(yè)項(xiàng)目投資合同
- (完整版)鋁礬土進(jìn)口合同中英文
- 《庖丁解牛》獲獎(jiǎng)?wù)n件(省級公開課一等獎(jiǎng))-完美版PPT
- 化工園區(qū)危險(xiǎn)品運(yùn)輸車輛停車場建設(shè)標(biāo)準(zhǔn)
- 6月大學(xué)英語四級真題(CET4)及答案解析
- 氣排球競賽規(guī)則
- 電梯維修保養(yǎng)報(bào)價(jià)書模板
- 危險(xiǎn)化學(xué)品目錄2023
- FZ/T 81024-2022機(jī)織披風(fēng)
- GB/T 33141-2016鎂鋰合金鑄錠
- JJF 1069-2012 法定計(jì)量檢定機(jī)構(gòu)考核規(guī)范(培訓(xùn)講稿)
- 綜合管廊工程施工技術(shù)概述課件
評論
0/150
提交評論