日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢(xún)
選擇下列產(chǎn)品馬上在線(xiàn)溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷(xiāo)解決方案
詳解java反射

相信很多人都知道反射可以說(shuō)是Java中最強(qiáng)大的技術(shù)了,它可以做的事情太多太多,很多優(yōu)秀的開(kāi)源框架都是通過(guò)反射完成的,本篇文章重點(diǎn)講解一下java反射。

遼陽(yáng)縣ssl適用于網(wǎng)站、小程序/APP、API接口等需要進(jìn)行數(shù)據(jù)傳輸應(yīng)用場(chǎng)景,ssl證書(shū)未來(lái)市場(chǎng)廣闊!成為成都創(chuàng)新互聯(lián)的ssl證書(shū)銷(xiāo)售渠道,可以享受市場(chǎng)價(jià)格4-6折優(yōu)惠!如果有意向歡迎電話(huà)聯(lián)系或者加微信:028-86922220(備注:SSL證書(shū)合作)期待與您的合作!

1. 什么是反射?

什么是反射?在官方文檔中是這樣說(shuō)的: Reflection is commonly used by programs which require the ability to examine ormodify the runtime behavior of applications running in the Java virtual machine. This is a relatively advanced feature and should be used only by developers whohave a strong grasp of the fundamentals of the language. With that caveat in mind, reflection is a powerful technique and can enable applications to perform operations which would otherwise be impossible

翻譯一下:

反射技術(shù)通常被用來(lái)檢測(cè)和改變應(yīng)用程序在 Java 虛擬機(jī)中的行為表現(xiàn)。它是一個(gè)相對(duì)而言比較高級(jí)的技術(shù),通常它應(yīng)用的前提是開(kāi)發(fā)者本身對(duì)于 Java 語(yǔ)言特性有很強(qiáng)的理解的基礎(chǔ)上。值得說(shuō)明的是,反射是一種強(qiáng)有力的技術(shù)特性,因此可以使得應(yīng)用程序執(zhí)行一些常規(guī)手段無(wú)法企及的目的。

個(gè)人理解:反射是一種很牛x的技術(shù),使用反射的條件是程序猿是一個(gè)大猿,對(duì)java的特性非常理解。反射的牛逼之處在于他可以完成一些非常規(guī)操作。

舉個(gè)栗子來(lái)說(shuō)明一下:

稍微想了一下,覺(jué)得用煮飯這個(gè)栗子來(lái)說(shuō)明吧,不知道準(zhǔn)不準(zhǔn)確(^,^)。平時(shí)我們?cè)诩依镆话闶怯秒婏堨襾?lái)煮飯的,煮飯的步驟一般是:淘米——>擦干鍋底——>把鍋放到電飯煲里——>合上蓋子,通電,電飯煲工作——>飯煮熟了,可以吃了,但現(xiàn)在有個(gè)需求,我要在煮飯的過(guò)程中加個(gè)雞蛋,這時(shí)怎么解決呢?是不是打開(kāi)正在通電煮飯的電飯煲,然后把雞蛋放進(jìn)去呢?(來(lái)自吃貨的需求^_^)其實(shí)反射就相當(dāng)于剛才加雞蛋的過(guò)程。所以反射很牛逼,他不按常規(guī)套路出牌,在程序運(yùn)行的過(guò)程中搞一些小動(dòng)作,以達(dá)到“吃貨”的目的。補(bǔ)充一下:“淘米——>擦干鍋底——>把鍋放到電飯煲里——>”這個(gè)過(guò)程可以看做編碼編譯過(guò)程,“——>合上蓋子,通電,電飯煲工作”可以看做是程序運(yùn)行過(guò)程,“——>飯煮熟了,可以吃了”可以看做程序運(yùn)行結(jié)束。

2.java中的反射機(jī)制

2.1 反射中常見(jiàn)的類(lèi)

理解反射機(jī)制時(shí),首先熟悉一下幾個(gè)類(lèi):

1)Class類(lèi)

Class類(lèi)實(shí)例表示正在運(yùn)行的Java應(yīng)用程序中的類(lèi)和接口。Class是普通類(lèi)、接口、枚舉類(lèi)、數(shù)組等的抽象,即它們的類(lèi)型就是Class,它們是Class的實(shí)例。

既然Class代表著類(lèi)和接口,那么我們可以通過(guò)他的實(shí)例(字節(jié)碼文件)來(lái)獲取對(duì)應(yīng)類(lèi)或接口的信息,如:注解、修飾符、類(lèi)型、類(lèi)的名稱(chēng)、屬性、方法、構(gòu)造方法、直接父類(lèi)和子類(lèi)等,還有可以創(chuàng)建它的實(shí)例,但只能調(diào)用無(wú)參構(gòu)造方法來(lái)創(chuàng)建。

什么看不懂?舉個(gè)栗子,我們都知道,生物可以分為動(dòng)物、植物、微生物和病毒等,而動(dòng)物又有人、喵星人、小狗等,植物、微生物和病毒也一樣。同樣,我們可以類(lèi)比一下,生物就是Class,動(dòng)物是普通類(lèi),植物是接口,微生物是枚舉類(lèi)、病毒是數(shù)組(枚舉和數(shù)組是特殊的類(lèi)),而人、喵星人、小狗是我們熟悉的對(duì)象,如圖 這下可整明白了吧,普通類(lèi)、接口、枚舉、數(shù)組其實(shí)都可以當(dāng)做Class的對(duì)象。

2)Field類(lèi)

Field表示類(lèi)的屬性,屬性含有修飾符、類(lèi)型、屬性名稱(chēng)和值。所以可以通過(guò)Field的實(shí)例獲取屬性的修飾符、類(lèi)型、屬性名稱(chēng),并且可以修改屬性的值。

3)Method類(lèi)

Method表示類(lèi)的成員方法,方法包括注解、修飾符、返回類(lèi)型、方法名,參數(shù)等。所以可以通過(guò)Method的實(shí)例獲取方法的的信息,如,注解、修飾符、返回類(lèi)型、方法名并且可以調(diào)用所表示的方法。

4)Constructor類(lèi)

Constructor表示構(gòu)造方法,可以通過(guò)Constructor的實(shí)例獲取構(gòu)造方法的信息,如,修飾符等,并且可以通過(guò)它來(lái)創(chuàng)建它所在類(lèi)的的實(shí)例。

5)Modifier類(lèi)

Modifier表示修飾符,可通過(guò)它來(lái)獲取修飾符的信息,例如何種修飾符等

6)Annotation

Annotation代表注解

以上類(lèi)都位于java.lang中

2.2 獲取Class對(duì)象的方法

了解了什么是反射后,是不是也想體驗(yàn)一下反射這種騷操作?

想秀操作,首先要獲取Class對(duì)象吧,因?yàn)镃lass對(duì)象是代表著各種類(lèi),有了它之后才可以得到類(lèi)的各種信息。獲取方法如下:

1)通過(guò)object.getClass()

public static void main(String[] args) {
     
      Car car = new Car();
     
      Class clazz = car.getClass();
  }

注意:此方法不適用于int、float等類(lèi)型

2)通過(guò)(類(lèi)型名).class、包裝類(lèi).Type

public static void main(String[] args) {
      Class clazz = Car.class;
      Class cls1 = int.class;
      Class cls2 = String.class;
      Class cls3=Iteger.Type
  }

3)通過(guò)Class.forClass(String 類(lèi)的全限定名)

1 try {
2    Class clz = Class.forName("com.frank.test.Car");
3 } catch (ClassNotFoundException e) {
4    e.printStackTrace();
5 }

采用哪種方法來(lái)獲取,看實(shí)際情況而定。

2.3獲取類(lèi)信息

有了Class對(duì)象后,就可以獲取類(lèi)的成員(方法+屬性)、注解和類(lèi)的修飾符等。上面也說(shuō)了,java中方法用Method類(lèi)表示、屬性用Field類(lèi)表示、注解用Annotation類(lèi)來(lái)表示、修飾符用Modifier類(lèi)表示。Class類(lèi)中有對(duì)應(yīng)的方法來(lái)獲取他們。如下:

2.3.1 獲取屬性Field的對(duì)象

//獲取所有的屬性,但不包括從父類(lèi)繼承下來(lái)的屬性
public Field[] getDeclaredFields() throws SecurityException
//獲取自身的所有的 public 屬性,包括從父類(lèi)繼承下來(lái)的。
public Field[] getFields() throws SecurityException
//獲取在本類(lèi)中聲明的指定的屬性,參數(shù)為屬性的名稱(chēng)
public Field getDeclaredField(String name)
//獲取指定的公有屬性,包括父類(lèi)的,參數(shù)為屬性的名稱(chēng)
public Field getField(String name)

2.3.2 獲取方法Method對(duì)象

//獲取本類(lèi)聲明指定的的方法,第一個(gè)參數(shù)是方法的名稱(chēng),后面的參數(shù)是方法參數(shù)類(lèi)型的類(lèi),
//如獲取setName(String name)方法,getDeclareMethod(“setName”,String.Class)
public Method getDeclaredMethod(String name, Class... parameterTypes)
//獲取公有的方法,包括父類(lèi)的
public Method getMethod(String name, Class... parameterTypes)
//獲取本類(lèi)中聲明的所有方法
public Method[] getDeclaredMethods()
//獲取所有的公有方法,包括父類(lèi)的
public Method[] getMethods()

2.3.3 獲取構(gòu)造器Constructor對(duì)象

//獲取本類(lèi)中指定的構(gòu)造方法
public Constructor getDeclaredConstructor(Class... parameterTypes)
//獲取指定的公有構(gòu)造方法
public Constructor getConstructor(Class... parameterTypes)
//獲取本類(lèi)中所有的構(gòu)造方法
public Constructor[] getDeclaredConstructors() throws SecurityException
//獲取本類(lèi)中所有的公有構(gòu)造方法
public Constructor[] getConstructors()

構(gòu)造方法的獲取與普通方法的獲取大致是一樣的。

——————————————————————

以上的方法都是在Class類(lèi)中,別傻傻不知道(別問(wèn)我怎么知道的>_>),然后通過(guò)Class對(duì)象調(diào)用就可以了。

這里只是列舉了常用類(lèi)信息的的獲取方法,其他信息的獲取方法,看API文檔吧,如注解、類(lèi)的Class的對(duì)象(額好像有點(diǎn)繞。。。)等.

2.4 獲取類(lèi)成員信息

上面只是獲取了類(lèi)的成員所代表類(lèi)的對(duì)象,我們還要使用他們或者獲取成員的信息(名稱(chēng)、修飾符等)。因?yàn)橛辛舜沓蓡T的對(duì)象,使用對(duì)象調(diào)用實(shí)例方法就可以了。

2.4.1 Field類(lèi)

Field類(lèi)的方法大概可以分為兩種,一種是獲取屬性的信息,另外一種是設(shè)置屬性的值。

第一種:

//返回由此 Field對(duì)象表示的字段的名稱(chēng)
String  getName()
//返回一個(gè) 類(lèi)對(duì)象標(biāo)識(shí)了此表示的字段的聲明類(lèi)型 Field對(duì)象。
Class  getType()
//返回由該 Field對(duì)象表示的字段的Java語(yǔ)言修飾符,作為整數(shù)。把整數(shù)作為Modifier的構(gòu)造方法的參數(shù),就可以獲取該整數(shù)代表的修飾符類(lèi)的對(duì)象了
int  getModifiers()
----------------------------------------------------------------

//獲取類(lèi)型為 int的靜態(tài)或?qū)嵗侄蔚闹?,或通過(guò)擴(kuò)展轉(zhuǎn)換轉(zhuǎn)換為類(lèi)型 int的另一個(gè)原始類(lèi)型的值。
int getInt(Object obj)
//獲取類(lèi)型為 long的靜態(tài)或?qū)嵗侄蔚闹担蛲ㄟ^(guò)擴(kuò)大轉(zhuǎn)換獲得可轉(zhuǎn)換為類(lèi)型 long的另一個(gè)基本類(lèi)型的值。
long getLong(Object obj)
......此處省略一堆get**(Object obj)的方法,屬性是什么基本類(lèi)型,就get什么就行了
14屬性是引用類(lèi)型,那么就調(diào)用以下方法
//返回該所表示的字段的 Field ,指定的對(duì)象上。  16 Object get(Object obj)

第二種:

//設(shè)置作為一個(gè)字段的值 double指定的對(duì)象上。  
void setDouble(Object obj, double d)
//設(shè)置作為一個(gè)字段的值 float指定的對(duì)象上。  
void setFloat(Object obj, float f)
//設(shè)置作為一個(gè)字段的值 int指定的對(duì)象上。
void setInt(Object obj, int i)
........此處省略一堆set**()方法,屬性是什么基本類(lèi)型就set什么就行了
屬性是引用類(lèi)型,那么就調(diào)用以下方法
//將指定對(duì)象參數(shù)上的此 Field對(duì)象表示的字段設(shè)置為指定的新值。
void  set(Object obj, Object value)

注意啦:如果沒(méi)有訪(fǎng)問(wèn)權(quán)限的話(huà),默認(rèn)是不能設(shè)置屬性值的,那??么辦呢?是不是就秀不了操作了?然而,前面也說(shuō)了,反射很牛逼,可以來(lái)一些非常規(guī)操作, 這時(shí)我們調(diào)用Class對(duì)象的setAccessible(true)方法就可以了! 是不是覺(jué)得反射可以很強(qiáng)? 2.4.2 Method類(lèi) Method類(lèi)的方法主要是獲取方法的信息 部分方法:

1 int getModifiers() //返回由該對(duì)象表示的可執(zhí)行文件的Java語(yǔ)言modifiers 。  
2 String getName() //返回由此 方法對(duì)象表示的方法的名稱(chēng),作為 String 。  
3 Annotation[][] getParameterAnnotations() //返回一個(gè) Annotation s的數(shù)組數(shù)組,表示由該對(duì)象表示的Executable的形式參數(shù)的聲明順序的 Executable 。  
4 int getParameterCount() //返回由此對(duì)象表示的可執(zhí)行文件的形式參數(shù)(無(wú)論是顯式聲明還是隱式聲明)的數(shù)量。  
5 Class[] getParameterTypes() //返回一個(gè) 類(lèi)對(duì)象的數(shù)組, 類(lèi)以聲明順序表示由該對(duì)象表示的可執(zhí)行文件的形式參數(shù)類(lèi)型。  

2.4.3 Constructor類(lèi) Constructor類(lèi)的方法主要是獲取構(gòu)方法的信息和創(chuàng)建對(duì)象

獲取方法信息:

1 int getModifiers() //返回由該對(duì)象表示的可執(zhí)行文件的Java語(yǔ)言modifiers 。  
2 String getName() //以字符串形式返回此構(gòu)造函數(shù)的名稱(chēng)。  
3 Annotation[][] getParameterAnnotations() //返回的數(shù)組的數(shù)組 Annotation表示的形參進(jìn)行注釋s時(shí),聲明順序的的 Executable該對(duì)象表示。  
4 int getParameterCount() //返回由此對(duì)象表示的可執(zhí)行文件的形式參數(shù)(無(wú)論是顯式聲明還是隱式聲明)的數(shù)量。  
5 Class[] getParameterTypes() //返回一個(gè) 類(lèi)對(duì)象的數(shù)組, 類(lèi)以聲明順序表示由該對(duì)象表示的可執(zhí)行文件的形式參數(shù)類(lèi)型。

創(chuàng)建對(duì)象的方法先不說(shuō),放到后面去。

2.5 反射創(chuàng)建對(duì)象和調(diào)用方法

2.5.1 創(chuàng)建普通類(lèi)的對(duì)象

創(chuàng)建普通類(lèi)的對(duì)象可以分為兩種方法

第一種:調(diào)用Class對(duì)象的方法

4 //首先獲取Class對(duì)象
5 Class clazz=Class.forClass("test.Student");
6 //創(chuàng)建對(duì)象
7 Student stu=(Student)clazz.newInstance();
注:此方法只能創(chuàng)建無(wú)參構(gòu)造函數(shù)的類(lèi)的對(duì)象

第二種:通過(guò)Constructor的newInstance()方法

//首先創(chuàng)建Class對(duì)象
Class clazz=Class.forClass("test.Student");
//獲取想調(diào)用的構(gòu)造函數(shù)
Constructor constructor=clazz.getConstructor(String.class, int.class);
//調(diào)用Constructor的newInstance()方法
Student stu=(Student)constructor.newInstance("大王",20);

2.5.2 創(chuàng)建數(shù)組

數(shù)組本質(zhì)上是一個(gè) Class,而在 Class 中存在一個(gè)方法用來(lái)識(shí)別它是否為一個(gè)數(shù)組。

反射創(chuàng)建數(shù)組是通過(guò) Array.newInstance(T.class,維數(shù)) 這個(gè)方法。

第一個(gè)參數(shù)指定的是數(shù)組內(nèi)的元素類(lèi)型,后面的是可變參數(shù),表示的是相應(yīng)維度的數(shù)組長(zhǎng)度限制。

比如,我要?jiǎng)?chuàng)建一個(gè) int2 的數(shù)組。

1 Int[][]  a=Array.newInstance(Integer.TYPE, 2, 3);

2.5.3 調(diào)用方法

用了上面的方法,就有Class對(duì)象,有方法Method對(duì)象,有實(shí)例,現(xiàn)在已經(jīng)萬(wàn)事俱備,只欠東風(fēng)了。

那我們?cè)趺凑{(diào)用方法呢?在Method類(lèi)有這么一個(gè)方法Object invoke(Object obj, Object… args),object為實(shí)例對(duì)象,args為調(diào)用方法的參數(shù)

來(lái)個(gè)栗子:

Class c = Class.forName("com.kal01.reflect05.Person");//獲取Class對(duì)象
Person p1 = (Person) c.newInstance();//獲取實(shí)例
Method m3 = c.getDeclaredMethod("test");//獲取方法
m3.setAccessible(true);//當(dāng)沒(méi)有訪(fǎng)問(wèn)權(quán)限時(shí),設(shè)置一下就可以
m3.invoke(p1);//調(diào)用方法
m3.setAccessible(false);//修改了訪(fǎng)問(wèn)權(quán)限,記得修改回來(lái)

2.6 靜態(tài)加載與動(dòng)態(tài)加載

看到這里是不是有個(gè)疑問(wèn),反射調(diào)用類(lèi)的方法好像除了復(fù)雜之外,跟我們平時(shí)調(diào)用沒(méi)什么區(qū)別。何必弄那么花里胡哨?

所以在這里簡(jiǎn)單說(shuō)一下靜態(tài)加載與動(dòng)態(tài)加載。

回想一下之前煮飯的那個(gè)栗子,靜態(tài)加載和動(dòng)態(tài)加載的這個(gè)例子有點(diǎn)相似。

靜態(tài)加載:我們?cè)诔绦蛑惺褂妙?lèi)時(shí),靜態(tài)加載是要求要使用的類(lèi)必須要求在編譯的時(shí)候存在,否則編譯器報(bào)錯(cuò),無(wú)法運(yùn)行程序。編碼時(shí)忘記導(dǎo)包時(shí),經(jīng)常會(huì)出現(xiàn)這種錯(cuò)誤。

動(dòng)態(tài)加載:利用反射來(lái)加載類(lèi)(即獲得Class對(duì)象),不要求我們?cè)诰幾g期存在要是用的那個(gè)類(lèi),在程序運(yùn)行時(shí),才去尋找類(lèi)(可以從jar包,網(wǎng)絡(luò)等尋找),然后把類(lèi)加載到方法區(qū)中,如果沒(méi)有找到這個(gè)類(lèi)會(huì)拋出ClassNotFoundException異常。

有圖有真相:

這下看出來(lái)反射的牛逼之處了吧,利用反射使用類(lèi)時(shí),并不需要這個(gè)類(lèi)在編譯期存在,這就增加了程序的靈活性,可以完成我們的騷操作!

最后總結(jié)一下:

使用反射時(shí),記住一句話(huà):老哥,穩(wěn)住,別翻車(chē)!


本文標(biāo)題:詳解java反射
文章路徑:http://www.5511xx.com/article/cocciop.html