Java反射機(jī)制詳解
本文較為詳細(xì)的分析了Java反射機(jī)制。分享給大家供大家參考,具體如下:
一、預(yù)先需要掌握的知識(shí)(java虛擬機(jī))
java虛擬機(jī)的方法區(qū):
java虛擬機(jī)有一個(gè)運(yùn)行時(shí)數(shù)據(jù)區(qū),這個(gè)數(shù)據(jù)區(qū)又被分為方法區(qū),堆區(qū)和棧區(qū),我們這里需要了解的主要是方法區(qū)。方法區(qū)的主要作用是存儲(chǔ)被裝載的類 的類型信息,當(dāng)java虛擬機(jī)裝載某個(gè)類型的時(shí)候,需要類裝載器定位相應(yīng)的class文件,然后將其讀入到j(luò)ava虛擬機(jī)中,緊接著虛擬機(jī)提取class 中的類型信息,將這些信息存儲(chǔ)到方法區(qū)中。這些信息主要包括:
1、這個(gè)類型的全限定名
2、這個(gè)類型的直接超類的全限定名
3、這個(gè)類型是類類型還是接口類型
4、這個(gè)類型的訪問修飾符
5、任何直接超接口的全限定名的有序列表
6、該類型的常量池
7、字段信息
8、方法信息
9、除了常量以外的所有類變量
10、一個(gè)到class類的引用
等等(讀者可以參考《深入java虛擬機(jī)》這本書的敘述)
Class類:
Class類是一個(gè)非常重要的java基礎(chǔ)類,每當(dāng)裝載一個(gè)新的類型的時(shí)候,java虛擬機(jī)都會(huì)在java堆中創(chuàng)建一個(gè)對(duì)應(yīng)于新類型的Class實(shí)例,該實(shí)例就代表此類型,通過該Class實(shí)例我們就可以訪問該類型的基本信息。上面說(shuō)到在方法區(qū)中會(huì)存儲(chǔ)某個(gè)被裝載類的類型信息,我們就可以通過 Class實(shí)例來(lái)訪問這些信息。比如,對(duì)于上面說(shuō)到的信息Class中都有對(duì)應(yīng)的方法,如下:
1、getName();這個(gè)類型的全限定名
2、getSuperClass();這個(gè)類型的直接超類的全限定名
3、isInterface();這個(gè)類型是類類型還是接口類型
4、getTypeParamters();這個(gè)類型的訪問修飾符
5、getInterfaces();任何直接超接口的全限定名的有序列表
6、getFields();字段信息
7、getMethods();方法信息
等等(讀者可以自己參看jdk幫助文檔,得到更多的信息)
二、java反射詳解
反射的概念:所謂的反射就是java語(yǔ)言在運(yùn)行時(shí)擁有一項(xiàng)自觀的能力,反射使您的程序代碼能夠得到裝載到JVM中的類的內(nèi)部信息,允許您執(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代 表的是類對(duì)象,Constructor-類的構(gòu)造器對(duì)象,F(xiàn)ield-類的屬性對(duì)象,Method-類的方法對(duì)象,通過這四個(gè)對(duì)象我們可以粗略的看到一個(gè)類的各個(gè)組成部分。其中最核心的就是Class類,它是實(shí)現(xiàn)反射的基礎(chǔ),它包含的方法我們?cè)诘谝徊糠忠呀?jīng)進(jìn)行了基本的闡述。應(yīng)用反射時(shí)我們最關(guān)心的一般是一個(gè)類的構(gòu)造器、屬性和方法,下面我們主要介紹Class類中針對(duì)這三個(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ù)(與接入級(jí)別無(wú)關(guān))
Constructor[] getDeclaredConstructors() -- 獲得類的所有構(gòu)造函數(shù)(與接入級(jí)別無(wú)關(guān))
2、獲得字段信息的方法
Field getField(String name) -- 獲得命名的公共字段
Field[] getFields() -- 獲得類的所有公共字段
Field getDeclaredField(String name) -- 獲得類聲明的命名的字段
Field[] getDeclaredFields() -- 獲得類聲明的所有字段
3、獲得方法信息的方法
Method getMethod(String name, Class[] params) -- 使用特定的參數(shù)類型,獲得命名的公共方法
Method[] getMethods() -- 獲得類的所有公共方法
Method getDeclaredMethod(String name, Class[] params) -- 使用特寫的參數(shù)類型,獲得類聲明的命名的方法
Method[] getDeclaredMethods() -- 獲得類聲明的所有方法
應(yīng)用反射的基本步驟:
1、獲得你想操作的類的Class對(duì)象;
方法一:Classc=Class.forName("java.lang.String") //這種方式獲得類的Class對(duì)象需要 包名.類名
方法二:對(duì)于基本數(shù)據(jù)類型可以用形如Class c=int.class或Class c=Integer.TYPE的語(yǔ)句
方法三:Class c=MyClass.class
2、調(diào)用Class中的方法得到你想得到的信息集合,如調(diào)用getDeclaredFields()方法得到類的所有屬性;
3、處理第2步中得到的信息,然后進(jìn)行你想做的實(shí)際操作。
反射實(shí)例:
下面我將針對(duì)類的構(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+"b="+b); } public static void main(String args[]){ try { Class cls =Class.forName("包名.ConstructorDemo"); Class partypes[] =new Class[2]; partypes[0] = Integer.TYPE; partypes[1] =Integer.TYPE; Constructor ct=cls.getConstructor(partypes); Object arglist[] =new Object[2]; arglist[0] = newInteger(37); arglist[1] = newInteger(47); Object retobj = ct.newInstance(arglist); } catch (Throwable e) { System.err.println(e);} } }
2、屬性
步驟為:通過反射機(jī)制得到某個(gè)類的某個(gè)屬性,然后改變對(duì)應(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"); 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)用對(duì)應(yīng)于這個(gè)類的某個(gè)實(shí)例的該方法
//通過使用方法的名字調(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 Class[2]; partypes[0] = Integer.TYPE; partypes[1] = Integer.TYPE; Method meth = cls.getMethod("add",partypes); MethodDemo1 methobj = new MethodDemo1(); Object arglist[] = new Object[2]; arglist[0] = new Integer(37); arglist[1] = new Integer(47); Object retobj= meth.invoke(methobj, arglist); Integer retval = (Integer)retobj; System.out.println(retval.intValue()); } catch (Throwable e) { System.err.println(e); } } }
三、java反射的應(yīng)用(Hibernate)
我們?cè)诘诙糠种袑?duì)java反射進(jìn)行了比較系統(tǒng)的闡述,也舉了幾個(gè)簡(jiǎn)單的實(shí)例,下面我們就來(lái)討論一下java反射的具體應(yīng)用。前面我們已經(jīng)知 道,Java反射機(jī)制提供了一種動(dòng)態(tài)鏈接程序組件的多功能方法,它允許程序創(chuàng)建和控制任何類的對(duì)象(根據(jù)安全性限制)之前,無(wú)需提前硬編碼目標(biāo)類。這些特 性使得反射特別適用于創(chuàng)建以非常普通的方式與對(duì)象協(xié)作的庫(kù)。例如,反射經(jīng)常在持續(xù)存儲(chǔ)對(duì)象為數(shù)據(jù)庫(kù)、XML或其它外部格式的框架中使用。下面我們就已 Hibernate框架為例像大家闡述一下反射的重要意義。
Hibernate是一個(gè)屏蔽了JDBC,實(shí)現(xiàn)了ORM的java框架,利用該框架我們可以拋棄掉繁瑣的sql語(yǔ)句而是利用Hibernate中 Session類的save()方法直接將某個(gè)類的對(duì)象存到數(shù)據(jù)庫(kù)中,也就是所涉及到sql語(yǔ)句的那些代碼Hibernate幫我們做了。這時(shí)候就出現(xiàn)了 一個(gè)問題,Hibernate怎樣知道他要存的某個(gè)對(duì)象都有什么屬性呢?這些屬性都是什么類型呢?如此,它在向數(shù)據(jù)庫(kù)中存儲(chǔ)該對(duì)象屬性時(shí)的sql語(yǔ)句該怎么構(gòu)造呢?解決這個(gè)問題的利器就是我們的java反射!
下面我們以一個(gè)例子來(lái)進(jìn)行闡述,比如我們定義了一個(gè)User類,這個(gè)User類中有20個(gè)屬性和這些屬性的get和set方法,相應(yīng)的在數(shù)據(jù)庫(kù)中 有一個(gè)User表,這個(gè)User表中對(duì)應(yīng)著20個(gè)字段。假設(shè)我們從User表中提取了一條記錄,現(xiàn)在需要將這條記錄的20個(gè)字段的內(nèi)容分別賦給一個(gè) User對(duì)象myUser的20個(gè)屬性,而Hibernate框架在編譯的時(shí)候并不知道這個(gè)User類,他無(wú)法直接調(diào)用myUser.getXXX或者 myUser.setXXX方法,此時(shí)就用到了反射,具體處理過程如下:
1、根據(jù)查詢條件構(gòu)造PreparedStament語(yǔ)句,該語(yǔ)句返回20個(gè)字段的值;
2、Hibernate通過讀取配置文件得到User類的屬性列表list(是一個(gè)String數(shù)組)以及這些屬性的類型;
3、創(chuàng)建myUser所屬類的Class對(duì)象c;c=myUser.getClass();
4、構(gòu)造一個(gè)for循環(huán),循環(huán)的次數(shù)為list列表的長(zhǎng)度;
4.1、讀取list[i]的值,然后構(gòu)造對(duì)應(yīng)該屬性的set方法;
4.2、判斷l(xiāng)ist[i]的類型XXX,調(diào)用PreparedStament語(yǔ)句中的getXXX(i),進(jìn)而得到i出字段的值;
4.3、將4.2中得到的值作為4.1中得到的set方法的參數(shù),這樣就完成了一個(gè)字段像一個(gè)屬性的賦值,如此循環(huán)即可;
看到了吧,這就是反射的功勞,如果沒有反射很難想象如果完成同樣的功能會(huì)有多么難!但是反射也有缺點(diǎn),比如性能比較低、安全性比較復(fù)雜等,這里就不在討論這些東西,感興趣的讀者可以在網(wǎng)上找到答案,有很多的!
希望本文所述對(duì)大家Java程序設(shè)計(jì)有所幫助。
- Java反射機(jī)制及Method.invoke詳解
- java 利用反射機(jī)制,獲取實(shí)體所有屬性和方法,并對(duì)屬性賦值
- Java通過反射機(jī)制動(dòng)態(tài)設(shè)置對(duì)象屬性值的方法
- JAVA反射機(jī)制實(shí)例教程
- java反射機(jī)制根據(jù)屬性名獲取屬性值的操作
- 通過java反射機(jī)制動(dòng)態(tài)調(diào)用某方法的總結(jié)(推薦)
- Java反射機(jī)制的實(shí)現(xiàn)詳解
- 利用java反射機(jī)制調(diào)用類的私有方法(推薦)
- java反射機(jī)制示例詳解
- 深入理解JAVA核心:揭秘反射機(jī)制的奧秘
相關(guān)文章
Intellij Idea 多模塊Maven工程中模塊之間無(wú)法相互引用問題
這篇文章主要介紹了Intellij Idea 多模塊Maven工程中模塊之間無(wú)法相互引用問題,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-01-01SpringBoot增強(qiáng)Controller方法@ControllerAdvice注解的使用詳解
這篇文章主要介紹了SpringBoot增強(qiáng)Controller方法@ControllerAdvice注解的使用詳解,@ControllerAdvice,是Spring3.2提供的新注解,它是一個(gè)Controller增強(qiáng)器,可對(duì)controller進(jìn)行增強(qiáng)處理,需要的朋友可以參考下2023-10-10Java數(shù)據(jù)結(jié)構(gòu)順序表用法詳解
順序表是計(jì)算機(jī)內(nèi)存中以數(shù)組的形式保存的線性表,線性表的順序存儲(chǔ)是指用一組地址連續(xù)的存儲(chǔ)單元依次存儲(chǔ)線性表中的各個(gè)元素、使得線性表中在邏輯結(jié)構(gòu)上相鄰的數(shù)據(jù)元素存儲(chǔ)在相鄰的物理存儲(chǔ)單元中,即通過數(shù)據(jù)元素物理存儲(chǔ)的相鄰關(guān)系來(lái)反映數(shù)據(jù)元素之間邏輯上的相鄰關(guān)系2021-10-10SpringMVC實(shí)現(xiàn)Validation校驗(yàn)過程詳解
這篇文章主要介紹了SpringMVC實(shí)現(xiàn)Validation校驗(yàn)過程詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-11-11java中設(shè)計(jì)模式(多例)的實(shí)例詳解
這篇文章主要介紹了java中設(shè)計(jì)模式(多例)的實(shí)例詳解的相關(guān)資料,希望通過本文能幫助到大家,需要的朋友可以參考下2017-09-09java?stream實(shí)現(xiàn)分組BigDecimal求和以及自定義分組求和
這篇文章主要給大家介紹了關(guān)于java?stream實(shí)現(xiàn)分組BigDecimal求和以及自定義分組求和的相關(guān)資料,Stream是Java8的一大亮點(diǎn),是對(duì)容器對(duì)象功能的增強(qiáng),它專注于對(duì)容器對(duì)象進(jìn)行各種非常便利、高效的聚合操作或者大批量數(shù)據(jù)操作,需要的朋友可以參考下2023-12-12