精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

反射和多態(tài)的實(shí)現(xiàn)原理詳解以及區(qū)別

開發(fā) 后端
反射和多態(tài)這兩種技術(shù)并無直接聯(lián)系,之所以把它們放在一起說,是因?yàn)椋贘ava技術(shù)體系中所提供的能夠讓我們在運(yùn)行時(shí)識別對象和類的類型信息的方式,一共有兩種:即反射和多態(tài)關(guān)鍵技術(shù)RTTI。

[[408287]]

 反射和多態(tài)

事實(shí)上,反射和多態(tài)這兩種技術(shù)并無直接聯(lián)系,之所以把它們放在一起說,是因?yàn)椋贘ava技術(shù)體系中所提供的能夠讓我們在運(yùn)行時(shí)識別對象和類的類型信息的方式,一共有兩種:即反射和多態(tài)關(guān)鍵技術(shù)RTTI

RTTI,即run-Time Type Identification運(yùn)行時(shí)類型判定,它的作用是在我們不知道某個(gè)對象的確切的類型信息時(shí),即某個(gè)對象是哪個(gè)類的實(shí)例的時(shí)候,可以通過RTTI相關(guān)的機(jī)制幫助我們在編譯時(shí)獲取對象的類型信息,這其實(shí)也就是多態(tài)的實(shí)現(xiàn)基礎(chǔ)。

反射機(jī)制允許我們在運(yùn)行時(shí)發(fā)現(xiàn)和使用類的信息。因此多態(tài)和反射兩者的最大的共同點(diǎn)在于,他們都是運(yùn)行時(shí)獲取程序信息的技術(shù)。反射技術(shù)對于java世界的眾多框架以及特性都發(fā)揮著至關(guān)重要的作用,博主認(rèn)為中文的基石一詞能夠準(zhǔn)確形容反射技術(shù)的地位,理解反射技術(shù)對于學(xué)習(xí)java相關(guān)技術(shù)的背后原理非常重要,許多java世界里的特性的實(shí)現(xiàn)原理背后都離不開反射。

讓我們先來看一下相對簡單一點(diǎn)的多態(tài)的相關(guān)知識以及實(shí)現(xiàn)原理RTTI相關(guān)的知識。

多態(tài)

什么是多態(tài)

首先明確一點(diǎn)我們在這里只考慮運(yùn)行時(shí)多態(tài),而不考慮編譯時(shí)多態(tài)(方法重載)。因此下列多態(tài)默認(rèn)都是指運(yùn)行時(shí)多態(tài)。

多態(tài)是面向?qū)ο缶幊汤锩娴母拍?,一個(gè)接口的多種不同的實(shí)現(xiàn)方式,即為多態(tài)。注意這里的接口,不應(yīng)理解得太死板,比如在java里面,繼承一個(gè)類和實(shí)現(xiàn)一個(gè)接口本質(zhì)上都是一種繼承行為,因此都應(yīng)該理解為多態(tài)的體現(xiàn)。

在計(jì)算機(jī)的世界里,尤其是編程的世界里,多態(tài)體現(xiàn)在:只有在運(yùn)行的時(shí)候才知道引用變量所指向的具體實(shí)例對象。且有三個(gè)必要的條件:

  •  繼承
  •  重寫/實(shí)現(xiàn)
  •  父類引用指向子類對象

多態(tài)的概念來源于生活,生活中的很多現(xiàn)象都是多態(tài)的體現(xiàn),例如打印機(jī),打印功能可以打印黑白色也可以打印彩色。同一款汽車可以用2.0l排量也可以有1.0l的排量。

多態(tài)的技術(shù)帶來的一個(gè)重要影響是:由于一個(gè)借口可能有多個(gè)實(shí)現(xiàn),而每個(gè)實(shí)現(xiàn)之間的大小,規(guī)模,是不一樣的。因此多態(tài)對內(nèi)存的分配是有影響的,不同的實(shí)現(xiàn)會(huì)有不同的內(nèi)存分配. 這一點(diǎn)與現(xiàn)實(shí)世界的多態(tài)例子相比就會(huì)非常有意思,第一,我們會(huì)發(fā)現(xiàn)軟件里的多態(tài)是動(dòng)態(tài)的多態(tài),而現(xiàn)實(shí)世界里的多態(tài)大部分是一個(gè)預(yù)先設(shè)定好的多態(tài)體現(xiàn),現(xiàn)實(shí)里的多態(tài)更多的類似于編譯時(shí)多態(tài),即方法重載,例如打印機(jī)的例子。

java里多態(tài)的具體用法

如上面我們提到的一樣多態(tài)通常有兩種實(shí)現(xiàn)方法:

  •  子類繼承父類(extends)
  •  類實(shí)現(xiàn)接口(implements)

核心之處就在于對父類方法的改寫或?qū)涌诜椒ǖ膶?shí)現(xiàn),以取得在運(yùn)行時(shí)不同的執(zhí)行效果。要使用多態(tài),在聲明對象時(shí)就應(yīng)該遵循一條法則:聲明的總是父類類型或接口類型,而創(chuàng)建的是實(shí)際類型.

以ArrayList為例子,要使用多態(tài)的特性,要按照如下方式定義

  1. List list = new ArrayList(); 

此外,在定義方法參數(shù)時(shí)也通??偸菓?yīng)該優(yōu)先使用父類類型或接口類型,例如: 

  1. public void test(List list); 

這樣聲明最大的好處在于它的靈活性,假如某一天ArrayList無法滿足要求,我們希望用LinkedList來代替它,那么只需要在對象創(chuàng)建的地方把new ArrayList()改為new LinkedList即可,其它代碼一概不用改動(dòng)。

多態(tài)的實(shí)現(xiàn)原理與RTTI

RTTI,即Run-Time Type Identification運(yùn)行時(shí)類型認(rèn)定,通過運(yùn)行時(shí)類型信息程序能夠使用父類的指針或引用來檢查這些指針或引用所指的對象的實(shí)際派生類型,是多態(tài)實(shí)現(xiàn)的技術(shù)基礎(chǔ)。RTTI的功能主要是通過Class類文件實(shí)現(xiàn)的,更精確一點(diǎn)是通過Class類文件的方法表實(shí)現(xiàn)的。

Class類是"類的類"(class of classes)。如果說類是對象的抽象的話,那么Class類就是對類的抽象。Class對象就是用來創(chuàng)建一個(gè)類的所有的常規(guī)對象的。每個(gè)類都有一個(gè)Class對象,每當(dāng)編寫好并且編譯了一個(gè)新的類,就會(huì)生成一個(gè)它對應(yīng)的Class對象,被保存在一個(gè)與類同名的.class文件中。java虛擬機(jī)中的被稱為類加載器的子系統(tǒng),就是專門拿來做生成這個(gè)類的Class對象的工作的。

每一個(gè)Class類的對象代表一個(gè)特定的類。請看如下代碼 

  1. import java.lang.Class;   
  2. public class Test {  
  3.     public static void main(String[] args) throws ClassNotFoundException {  
  4.         Cycle unicycle = new Unicycle("Unicycle");  
  5.         Cycle.ride(unicycle);  
  6.         Class c1 = unicycle.getClass();//獲取clas對象  
  7.         System.out.println(c1.getName());     
  8.         Cycle bicycle = new Bicycle("Bicycle");  
  9.         Cycle.ride(bicycle);  
  10.         Class c2 = Class.forName("basic.Bicycle");//獲取clas對象  
  11.         System.out.println(c2.getName());  
  12.         Cycle tricycle = new Tricycle("Tricycle");  
  13.         Cycle.ride(tricycle);  
  14.         Class c3      = Tricycle.class;//獲取clas對象  
  15.         System.out.println(c3.getName());  
  16.     } 
  17.  
  18. //父類  
  19. class Cycle {  
  20.     private String name;  
  21.     public Cycle(String str) {  
  22.         name = str 
  23.     }  
  24.     public static void ride(Cycle c) {  
  25.         System.out.println(c.name + "is riding"); 
  26.     }  
  27.  
  28. class Unicycle extends Cycle {  
  29.     private String name;   
  30.     public Unicycle(String str) {  
  31.         super(str);  
  32.         name = str
  33.      }  
  34. class Bicycle extends Cycle {  
  35.     private String name;  
  36.     public Bicycle(String str) {  
  37.         super(str);  
  38.         name = str 
  39.     }  
  40.   
  41. class Tricycle extends Cycle {  
  42.     private String name;   
  43.     public Tricycle(String str) {  
  44.         super(str);  
  45.         name = str 
  46.     }  

這是一個(gè)普通的多態(tài)的示例程序,但是我在每一處多態(tài)調(diào)用時(shí),分別去獲取了他們的class對象并打印出來。打印結(jié)果如下: 

  1. Unicycleis riding  
  2. basic.Unicycle  
  3. Bicycleis riding  
  4. basic.Bicycle  
  5. Tricycleis riding  
  6. basic.Tricycle 

可以發(fā)現(xiàn)即使我們將對象的引用向上轉(zhuǎn)型,對象所指向的Class類對象依然是實(shí)際的實(shí)現(xiàn)類。

Java中每個(gè)對象都有相應(yīng)的Class類對象,因此,我們隨時(shí)能通過Class對象知道某個(gè)對象“真正”所屬的類。無論我們對引用進(jìn)行怎樣的類型轉(zhuǎn)換,對象本身所對應(yīng)的Class對象都是同一個(gè)。這意味著java在運(yùn)行時(shí)的確能確定真正的實(shí)現(xiàn)類是哪一個(gè)。

下面從虛擬機(jī)運(yùn)行時(shí)的角度來簡要介紹多態(tài)的實(shí)現(xiàn)原理,這里以Java虛擬機(jī)規(guī)范的實(shí)現(xiàn)為例。

在JVM執(zhí)行Java字節(jié)碼時(shí),類型信息被存放在方法區(qū)中,通常為了優(yōu)化對象調(diào)用方法的速度,方法區(qū)的類型信息中增加一個(gè)指針,該指針指向一張記錄該類方法入口的表(稱為方法表),表中的每一項(xiàng)都是指向相應(yīng)方法的指針。

方法表的構(gòu)造如下:

由于Java的單繼承機(jī)制,一個(gè)類只能繼承一個(gè)父類,而所有的類又都繼承自O(shè)bject類。方法表中最先存放的是Object類的方法,接下來是該類的父類的方法,最后是該類本身的方法。方法表從上至下如下圖所示

這里關(guān)鍵的地方在于,如果子類改寫了父類的方法,那么子類和父類的那些同名方法共享一個(gè)方法表項(xiàng),都被認(rèn)作是父類的方法。如下所示

注意這里只有非私有的實(shí)例方法才會(huì)出現(xiàn),并且靜態(tài)方法也不會(huì)出現(xiàn)在這里,原因很容易理解:靜態(tài)方法跟對象無關(guān),可以將方法地址直接引用,而不像實(shí)例方法需要間接引用。

更深入地講,靜態(tài)方法是由虛擬機(jī)指令invokestatic調(diào)用的,私有方法和構(gòu)造函數(shù)則是由invokespecial指令調(diào)用,只有被invokevirtual和invokeinterface指令調(diào)用的方法才會(huì)在方法表中出現(xiàn)。

由于以上方法的排列特性(Object——父類——子類),使得方法表的偏移量總是固定的。例如,對于任何類來說,其方法表中equals方法的偏移量總是一個(gè)定值,所有繼承某父類的子類的方法表中,其父類所定義的方法的偏移量也總是一個(gè)定值。

前面說過,方法表中的表項(xiàng)都是指向該類對應(yīng)方法的指針,這里就開始了多態(tài)的實(shí)現(xiàn):

假設(shè)Class B是Class A的子類,并且B重寫了A的方法method(),那么在B的方法表中,method()方法的指針指向的就是B的method方法入口而非類A的同名方法入口,也就是說,在虛擬機(jī)編譯生成B的Class文件中的方法表時(shí),就實(shí)現(xiàn)了多態(tài),之后只需讓對應(yīng)的指令調(diào)用即可。

而對于A來說,它的方法表中的method方法則會(huì)指向其自身的method方法而非其父類的(這在類加載器載入該類時(shí)已經(jīng)保證,同時(shí)JVM會(huì)保證總是能從對象引用指向正確的類型信息)。

結(jié)合方法指針偏移量是固定的以及指針總是指向?qū)嶋H類的方法域,我們不難發(fā)現(xiàn)多態(tài)的機(jī)制就在這里:

在調(diào)用方法時(shí),實(shí)際上必須首先完成實(shí)例方法的符號引用解析,結(jié)果是該符號引用被解析為方法表的偏移量。虛擬機(jī)通過對象引用得到方法區(qū)中類型信息的入口,查詢類的方法表,當(dāng)將子類對象聲明為父類類型時(shí),形式上調(diào)用的是父類方法,此時(shí)虛擬機(jī)會(huì)從實(shí)際類的方法表(雖然聲明的是父類,但是實(shí)際上這里的類型信息中存放的是子類的信息)中查找該方法名對應(yīng)的指針(這里用“查找”實(shí)際上是不合適的,前面提到過,方法的偏移量是固定的,所以只需根據(jù)偏移量就能獲得指針),進(jìn)而就能指向?qū)嶋H類的方法了。

我們的故事還沒有結(jié)束,事實(shí)上上面的過程僅僅是利用繼承實(shí)現(xiàn)多態(tài)的內(nèi)部機(jī)制,多態(tài)的另外一種實(shí)現(xiàn)方式:實(shí)現(xiàn)接口相比而言就更加復(fù)雜,原因在于,Java的單繼承保證了類的線性關(guān)系,而接口可以同時(shí)實(shí)現(xiàn)多個(gè),這樣光憑偏移量就很難準(zhǔn)確獲得方法的指針。所以在JVM中,多態(tài)的實(shí)例方法調(diào)用實(shí)際上有兩種指令:

  •  invokevirtual指令用于調(diào)用聲明為類的方法;
  •  invokeinterface指令用于調(diào)用聲明為接口的方法。

當(dāng)使用invokeinterface指令調(diào)用方法時(shí),就不能采用固定偏移量的辦法,只能老老實(shí)實(shí)挨個(gè)找了(當(dāng)然實(shí)際實(shí)現(xiàn)并不一定如此,JVM規(guī)范并沒有規(guī)定究竟如何實(shí)現(xiàn)這種查找,不同的JVM實(shí)現(xiàn)可以有不同的優(yōu)化算法來提高搜索效率)。

我們不難看出,在性能上,調(diào)用接口引用的方法通常總是比調(diào)用類的引用的方法要慢。這也告訴我們,在類和接口之間優(yōu)先選擇接口作為設(shè)計(jì)并不總是正確的,當(dāng)然設(shè)計(jì)問題不在本文探討的范圍之內(nèi),但顯然具體問題具體分析仍然不失為更好的選擇。

這就是多態(tài)的原理。總結(jié)起來說就是兩點(diǎn):

  1.  是方法表起了決定性作用,如果子類改寫了父類的方法,那么子類和父類的那些同名方法共享一個(gè)方法表項(xiàng),都被認(rèn)作是父類的方法,因此可以寫成父類引用指向子類對象的形式。
  2.  類和接口的多態(tài)實(shí)現(xiàn)不一樣,類的方法表可以使用固定偏移,但接口只能挨個(gè)找,原因是接口的實(shí)現(xiàn)不是確定唯一的。

關(guān)于RTTI技術(shù),典型的應(yīng)用除了多態(tài)這樣的類型轉(zhuǎn)換,以及根據(jù)類生成Class對象這兩種形式以外。還有一種常見的用法,就是關(guān)鍵字Instanceof。Instanceof的作用是返回一個(gè)布爾值,告訴我們一個(gè)對象是不是某個(gè)特定類的一個(gè)實(shí)例。例如: 

  1. if(x instanceof Dog){   

即在判斷x對象是不是Dog類的一個(gè)實(shí)例。

思考題:為什么使用多態(tài)創(chuàng)建一個(gè)對象引用之后,有的方法引用中不能調(diào)用?

反射

RTTI的作用是,當(dāng)我們不知道一個(gè)對象的確切的類型的時(shí)候,可以通過RTTI來獲取。但是這個(gè)功能存在一個(gè)限制:要通過RTTI獲取的類型信息必須是在編譯時(shí)已知的,這句話怎么理解,我們通過多態(tài)的例子來說明:

  1. Animal dog = new Dog(); 

上述代碼定義的引用是Animal類型,但是在編譯時(shí)期,虛擬機(jī)可通過我們后面的new的代碼獲取到這個(gè)Animal的真正類型,這就是編譯時(shí)已知,這里有個(gè)前提條件是代碼里面其實(shí)是要給虛擬機(jī)留下這樣的判斷信息的。這事實(shí)上是一個(gè)限制。

原因在于,我們在很多時(shí)候并不能在編譯時(shí)獲知某個(gè)對象所述的類。例如,我們有個(gè)api的功能是接收字段并解析它屬于哪個(gè)類,但是傳入的字段可能是我們定義好的多個(gè)類的其中一個(gè),這個(gè)時(shí)候就沒辦法在編譯時(shí)知道類型信息了。而只能在運(yùn)行時(shí)通過傳入的字段進(jìn)行判斷才有可能知道。

什么是反射

反射的定義如下:java程序在運(yùn)行狀態(tài)中,對于任意一個(gè)類,都能夠在運(yùn)行時(shí)知道這個(gè)類的所有屬性和方法;對于任意一個(gè)對象,都能夠調(diào)用它的任意方法和屬性;這種動(dòng)態(tài)獲取信息以及動(dòng)態(tài)調(diào)用對象方法的功能稱為java語言的反射機(jī)制。

上面這段話需要非常仔細(xì)的理解,我想通過問問題的形式來幫助讀者理解反射的概念。

問題1:什么是類的屬性和方法?

這個(gè)問題比較愚蠢,甚至有侮辱人的智商之嫌,但是博主的本意肯定不是這樣。這是一個(gè)很簡單問題,假設(shè)我們有下面代碼: 

  1. public class Test{  
  2.        private String s;   
  3.     public void doNothing(){    
  4.     }  

那么,字符串s就是它的屬性,doNothing就是它的方法

問題2:什么叫一個(gè)類的所有屬性和方法

答:所有這個(gè)類中定義的成員變量,以及所有屬于這個(gè)類的方法。

問題3:問題2中的所有屬性和方法包含私有的嗎?

答案是包含的

問題4:任何一個(gè)類,除了屬性和方法,還有別的內(nèi)容嗎?

答案是沒有了。注意,內(nèi)部類不屬于外部類,本質(zhì)上是兩個(gè)類。

問題5:什么叫獲取一個(gè)方法,什么叫獲取一個(gè)屬性?

這是一個(gè)很好的問題,理解了這個(gè)問題之后也就不會(huì)覺得反射過于抽象了。java當(dāng)中提供了專門的方法的抽象Method類和專門的屬性的抽象Field類,以及專門的所有類的抽象Class類,并提供了一系列的方法,來幫助我們獲取一個(gè)類的屬性和方法。

獲取到的屬性和方法,將以普通對象的方式存在。與我們自己寫的類并無任何區(qū)別。下面是一個(gè)代碼例子: 

  1. public class MethodClass {   
  2.     public static void main(String[] args) throws Exception {  
  3.         //1.獲取Class對象  
  4.         Class xxxClass = Class.forName("com.XXX.XXX");  
  5.         //2.獲取所有公有方法  
  6.         Method[] methodArray = xxxClass .getMethods(); 
  7.         //3.獲取字段  
  8.         Field[] fieldArray = xxxClass .getFields();  
  9.     }  

反射的實(shí)現(xiàn)原理

Class類與java.lang.reflect庫一起對反射的概念提供了技術(shù)支持。java.lang.reflect類庫包含了Field類,Method類以及Constructor類。這些類用來表示未知類里對應(yīng)的成員。Class類提供了獲取getFields()、getMethods()和getConstructors()等方法,而這些方法的返回值類型就定義在java.lang.reflect當(dāng)中。

如果不知道某個(gè)對象的確切類型(即list引用到底是ArrayList類型還是LinkedList類型),RTTI可以告訴你,但是有一個(gè)前提:這個(gè)類型在編譯時(shí)必須已知,這樣才能使用RTTI來識別它。

要想理解反射的原理,必須要結(jié)合類加載機(jī)。反射機(jī)制并沒有什么神奇之處,當(dāng)通過反射與一個(gè)未知類型的對象打交道時(shí),JVM只是簡單地檢查這個(gè)對象,看它屬于哪個(gè)特定的類,然后再通過拿到的某一個(gè)類的全限定名去找這個(gè)類的Class文件 。因此,那個(gè)類的.class對于JVM來說必須是可獲取的,要么在本地機(jī)器上,要么從網(wǎng)絡(luò)獲取。所以對于RTTI和反射之間的真正區(qū)別只在于:

  •  RTTI,編譯器在編譯時(shí)打開和檢查.class文件
  •  反射,運(yùn)行時(shí)打開和檢查.class文件

對于反射機(jī)制而言.class文件在編譯時(shí)是不可獲取的,所以是在運(yùn)行時(shí)獲取和檢查.class文件。

總結(jié)起來說就是,反射是通過Class類和java.lang.reflect類庫一起支持而實(shí)現(xiàn)的,其中每一個(gè)Class類的對象都對應(yīng)了一個(gè)類,這些信息在編譯時(shí)期就已經(jīng)被存在了.class文件里面了,Class 對象是在加載類時(shí)由 Java 虛擬機(jī)以及通過調(diào)用類加載器中的defineClass方法自動(dòng)構(gòu)造的。對于我們定義的每一個(gè)類,在虛擬機(jī)中都有一個(gè)應(yīng)的Class對象。

那么在運(yùn)行時(shí)期,無論是通過字面量還是forName方法獲取Class對象,都是去根據(jù)這個(gè)類的全限定名(全限定名必須是唯一的,這也間接回答了為什么類名不能重復(fù)這個(gè)問題。)然后獲取對應(yīng)的Class對象

總結(jié): java虛擬機(jī)幫我們生成了類的class對象,而通過類的全限定名,我們可以去獲取這個(gè)類的字節(jié)碼.class文件,然后再獲取這個(gè)類對應(yīng)的class對象,再通過class對象提供的方法結(jié)合類Method,Filed,Constructor,就能獲取到這個(gè)類的所有相關(guān)信息. 獲取到這些信息之后,就可以使用Constructor創(chuàng)建對象,用get和set方法讀取和修改與Field對象相關(guān)的字段,用invoke方法調(diào)用與Method對象關(guān)聯(lián)的方法。

反射的應(yīng)用

反射機(jī)制非常重要,應(yīng)用也非常之廣泛。在使用反射時(shí),我們的代碼里面可以出現(xiàn)任何一個(gè)具體的構(gòu)造器,字段信息,方法,但是卻能動(dòng)態(tài)的生成對象,調(diào)用他們的方法,這是一個(gè)非常通用的功能,由此帶來的價(jià)值也是驚人的。反射比較出名的應(yīng)用有:

  1.  Spring/Mybatis等框架,行內(nèi)有一句這樣的老話:反射機(jī)制是Java框架的基石。最經(jīng)典的就是xml的配置模式。
  2.  JDBC 的數(shù)據(jù)庫的連接
  3.  動(dòng)態(tài)生成對象,應(yīng)用于工廠模式中. spring的bean容器也就是一個(gè)工廠
  4.  jdk動(dòng)態(tài)代理,利用反射獲取傳入接口的實(shí)現(xiàn)類
  5.  注解機(jī)制的實(shí)現(xiàn),利用反射可以獲取每一個(gè)filed,F(xiàn)iled類提供了getDeclaredAnnotations方法以數(shù)組形式返回這個(gè)字段所有的注解....
  6.  編輯器代碼自動(dòng)提示的實(shí)現(xiàn)

反射的弊端

1.性能

反射包括了一些動(dòng)態(tài)類型,所以 JVM 無法對這些代碼進(jìn)行優(yōu)化。因此,反射操作的效率要比那些非反射操作低得多。我們應(yīng)該避免在經(jīng)常被 執(zhí)行的代碼或?qū)π阅芤蠛芨叩某绦蛑惺褂梅瓷洹?/p>

2.安全

使用反射技術(shù)要求程序必須在一個(gè)沒有安全限制的環(huán)境中運(yùn)行。如果一個(gè)程序必須在有安全限制的環(huán)境中運(yùn)行,如 Applet,那么這就是個(gè)問題了。

3.內(nèi)部暴露

由于反射允許代碼執(zhí)行一些在正常情況下不被允許的操作(比如訪問私有的屬性和方法),所以使用反射可能會(huì)導(dǎo)致意料之外的副作用--代碼有功能上的錯(cuò)誤,降低可移植性。反射代碼破壞了抽象性,因此當(dāng)平臺發(fā)生改變的時(shí)候,代碼的行為就有可能也隨著變化。

4.喪失了編譯時(shí)類型檢查的好處,包括異常檢查。如果程序企圖用反射去調(diào)用不存在或者不可訪問方法,在運(yùn)行時(shí)將會(huì)失敗。

5.從代碼規(guī)范的角度來說,執(zhí)行反射訪問所需要的代碼非常笨拙和冗長。這樣的代碼閱讀起來很困難

核心反射機(jī)制最初是為了基于組件的應(yīng)用創(chuàng)建工具而設(shè)計(jì)的,如spring。這類工具通常需要裝載類,并且用反射功能找出它們支持哪些方法和構(gòu)造器。這些工具允許用戶交互式的構(gòu)建訪問這些類的應(yīng)用程序。

反射功能只是在應(yīng)用程序設(shè)計(jì)階段被用到,通常,普通應(yīng)用程序運(yùn)行時(shí)不應(yīng)該以反射方式訪問對象。對于特定的復(fù)雜系統(tǒng)編程任務(wù),它也許是非常必要的,但它也有一些缺點(diǎn),如果你編寫的程序必須要與編譯時(shí)未知的類一起工作,如有可能就使用反射機(jī)制來實(shí)例化對象,而訪問對象時(shí)則使用編譯時(shí)已知的某個(gè)接口或者超類。

基于此,在effective java也總結(jié)了一條接口優(yōu)先于反射機(jī)制的開發(fā)原則。

反射相關(guān)類

Class類

關(guān)于Class類請參考博客:[面向?qū)ο骫 類與對象與Java里的Class類解析

Field類

即字段類,我們可以通過一個(gè)類的Class對象獲取其Field類的對象,然后java當(dāng)中提供了這個(gè)Field類來提供反射獲取字段的相關(guān)信息,以及進(jìn)行一些操作,比如set一個(gè)字段的值等功能。

Method類

即方法類,我們可以通過一個(gè)類的Class對象獲取其Method類的一個(gè)實(shí)例對象,并且使用獲得的Method對象去獲取這個(gè)方法的相關(guān)信息,以及調(diào)用這個(gè)方法的功能。

以上三個(gè)類建議讀者直接查看源代碼,看看他們提供的方法,就會(huì)理解得更加清楚。

反射應(yīng)用實(shí)例

下面的代碼是使用反射獲取方法的例子程序

model類 

  1. package com.dr.Reflection.getMethodByReflect;   
  2. public class Student {  
  3.     //**************成員方法***************//  
  4.     public void show1(String s) {  
  5.         System.out.println("調(diào)用了:公有的,String參數(shù)的show1(): s = " + s);  
  6.     }  
  7.     protected void show2() {  
  8.         System.out.println("調(diào)用了:受保護(hù)的,無參的show2()");  
  9.     }  
  10.     void show3() {  
  11.         System.out.println("調(diào)用了:默認(rèn)的,無參的show3()");  
  12.     }  
  13.     private String show4(int age) {  
  14.         System.out.println("調(diào)用了,私有的,并且有返回值的,int參數(shù)的show4(): age = " + age);  
  15.         return "abcd";  
  16.     }  

測試類 

  1. package com.dr.Reflection.getMethodByReflect;  
  2. import java.lang.reflect.Method;  
  3. /*  
  4.  * 獲取成員方法并調(diào)用:  
  5.  *  
  6.  * 1.批量的:  
  7.  *      public Method[] getMethods():獲取所有"公有方法";(包含了父類的方法也包含Object類)  
  8.  *      public Method[] getDeclaredMethods():獲取所有的成員方法,包括私有的(不包括繼承的)  
  9.  * 2.獲取單個(gè)的:  
  10.  *      public Method getMethod(String name,Class<?>... parameterTypes):  
  11.  *                  參數(shù):  
  12.  *                      name : 方法名;  
  13.  *                      Class ... : 形參的Class類型對象  
  14.  *      public Method getDeclaredMethod(String name,Class<?>... parameterTypes)  
  15.  *  
  16.  *   調(diào)用方法:  
  17.  *      Method --> public Object invoke(Object obj,Object... args):  
  18.  *                  參數(shù)說明:  
  19.  *                  obj : 要調(diào)用方法的對象;  
  20.  *                  args:調(diào)用方式時(shí)所傳遞的實(shí)參;  
  21. ):  
  22.  */  
  23. public class MethodClass {  
  24.     public static void main(String[] args) throws Exception {  
  25.         //1.獲取Class對象  
  26.         Class stuClass = Class.forName("com.dr.Reflection.getMethodByReflect.Student");  
  27.         //2.獲取所有公有方法  
  28.         System.out.println("***************獲取所有的”公有“方法*******************");  
  29.         stuClass.getMethods();  
  30.         Method[] methodArray = stuClass.getMethods();  
  31.         for(Method m : methodArray){  
  32.             /*  
  33.             注意,這里雖然student類自身只寫了一個(gè)public方法,但是由于java所有的類都繼承于object類,  
  34.             因此object類中所有的public方法也會(huì)被打印出來  
  35.              */  
  36.             System.out.println(m);  
  37.         }  
  38.         System.out.println("***************獲取所有的方法,包括私有的*******************");  
  39.         methodArray = stuClass.getDeclaredMethods();  
  40.         for(Method m : methodArray){//不包含父類的,僅僅是這個(gè)自身定義的方法  
  41.             System.out.println(m);  
  42.         }  
  43.         System.out.println("***************獲取公有的show1()方法*******************");  
  44.         Method m = stuClass.getMethod("show1", String.class);//根據(jù)方法名稱,以及參數(shù),獲取方法對象  
  45.         System.out.println(m);  
  46.         //實(shí)例化一個(gè)Student對象  
  47.         Object obj = stuClass.getConstructor().newInstance();  
  48.         m.invoke(obj, "劉德華");  
  49.         System.out.println("***************獲取私有的show4()方法******************");  
  50.         m = stuClass.getDeclaredMethod("show4", int.class);  
  51.         System.out.println(m);  
  52.         m.setAccessible(true);//解除私有限定 
  53.         Object result = m.invoke(obj, 20);//需要兩個(gè)參數(shù),一個(gè)是要調(diào)用的對象(獲取有反射),一個(gè)是實(shí)參  
  54.         System.out.println("返回值:" + result);  
  55.     }  

一些問題

private修飾的方法可以通過反射訪問,那么private意義何在?

答:首先java的private修飾符并不是為了安全性設(shè)計(jì)的,private并不是解決“安全”問題的。private想表達(dá)的不是“安全性”的意思,而是面向?qū)ο缶幊痰姆庋b概念,是一種編譯器可以幫助我們在設(shè)計(jì)上的一個(gè)點(diǎn)。

private的設(shè)計(jì)理念是對一個(gè)類的封裝,而封裝帶來的好處是,在項(xiàng)目開發(fā)過程當(dāng)中,修改一個(gè)類的private屬性是不影響使用的,因?yàn)椴淮嬖趯rivate代碼的顯式引用。

反射技術(shù)主要是為實(shí)現(xiàn)一些開發(fā)工具以及框架服務(wù)。在實(shí)際的開發(fā)過程當(dāng)中,我們應(yīng)該盡量避免使用反射。而在使用反射時(shí)也要非常小心。另外,關(guān)注Java知音公眾號,回復(fù)“后端面試”,送你一份面試題寶典!

反射和多態(tài)的區(qū)別

  •  同為運(yùn)行時(shí)獲取信息,多態(tài)獲取的信息僅僅在于確定方法應(yīng)用所指向的實(shí)際對象。而反射在于獲取一個(gè)類的所用信息。
  •  多態(tài)是一種面向?qū)ο笳Z言的機(jī)制。而反射技術(shù)是java提供的專門用于動(dòng)態(tài)獲取類的信息的技術(shù)。 

 

責(zé)任編輯:龐桂玉 來源: Java知音
相關(guān)推薦

2009-08-28 13:12:56

C#反射實(shí)例C#反射

2011-04-06 08:57:07

C++java多態(tài)

2023-11-16 09:10:18

多態(tài)封裝繼承

2022-09-21 11:54:22

TCPUDP協(xié)議

2023-03-01 10:37:51

2021-04-15 09:07:52

hotspotJavaC++

2023-07-11 08:00:00

2021-02-07 09:36:20

LongAdderJDK8開發(fā)

2011-04-12 10:40:04

C++多態(tài)

2024-03-14 14:56:22

反射Java數(shù)據(jù)庫連接

2020-01-06 10:58:18

JvmGC機(jī)制虛擬機(jī)

2018-07-06 15:30:14

DubboSPIJDK

2019-06-12 15:07:24

JVMStackHeap

2009-08-31 16:23:13

C#接口

2015-03-23 10:04:43

c++編譯器c++實(shí)現(xiàn)原理總結(jié)

2024-06-21 09:28:43

2022-12-19 08:00:00

SpringBootWeb開發(fā)

2015-07-10 12:23:05

JsPatch實(shí)現(xiàn)原理

2022-02-09 14:47:28

cookie瀏覽器服務(wù)器

2011-05-26 15:23:34

JavaReflection
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號

婷婷精品进入| 欧美亚洲二区| 99re6这里只有精品视频在线观看| 国外成人性视频| 亚洲av网址在线| 天天综合网站| 亚洲自拍偷拍麻豆| 日本10禁啪啪无遮挡免费一区二区 | 99国产精品白浆在线观看免费| 国产 欧美 精品| 首页综合国产亚洲丝袜| 麻豆乱码国产一区二区三区| 水蜜桃av无码| 91精品亚洲一区在线观看| 亚洲国产中文字幕在线视频综合 | 超碰91在线播放| 美女高潮视频在线看| 国产精品久久久久9999吃药| 国产精品区一区| 亚洲自拍第二页| 香蕉成人久久| 欧美激情三级免费| 乱老熟女一区二区三区| 亚洲都市激情| 精品久久久久久久久久久久久久久 | 欧美黄色网页| 亚洲成a人片在线不卡一二三区| 亚洲精品欧美精品| 丝袜+亚洲+另类+欧美+变态| 国产精品综合在线视频| 国产精品你懂得| 日韩不卡视频在线| 亚洲视频日本| 欧美成人精品在线观看| 日本美女bbw| 久久夜色电影| 精品美女被调教视频大全网站| jizz大全欧美jizzcom| 一个人看的www视频在线免费观看| 亚洲另类中文字| 亚洲一区二区三区色| 国产天堂在线| 久久精品夜色噜噜亚洲a∨| 精品视频一区在线| 黄色一级大片在线免费看国产| 国产美女娇喘av呻吟久久| 国产精品丝袜久久久久久不卡| 欧美黑人一区二区| 亚洲作爱视频| 欧美亚洲另类视频| 日韩在线观看第一页| 影音先锋在线一区| 97国产精品视频| 日韩三级免费看| 伊人久久成人| 97超级碰碰碰久久久| 国产手机在线视频| 亚洲精品社区| 欧美在线视频观看| 欧美日韩一二三四区| 久久精品123| 国产精品成久久久久三级| 波多野结衣在线观看视频| 日韩电影网1区2区| 国产精品一区久久久| 中文字幕久久久久| 寂寞少妇一区二区三区| 91情侣在线视频| 精品国产va久久久久久久| 国产精品77777竹菊影视小说| av在线不卡一区| 亚洲欧美激情在线观看| av资源站一区| 欧美中日韩一区二区三区| av中文在线| 亚洲人成7777| xxxx18hd亚洲hd捆绑| 中文字幕资源网在线观看免费 | 色片在线免费观看| www久久久| 亚洲精品一区二区三区精华液| 亚洲久久久久久| 精品福利久久久| 日韩一区二区三区在线播放| 欧美黄色免费观看| 国产手机视频一区二区| 国产精品久久久久久久久久久久| 国产精品久久久久久免费| 成人午夜av在线| 欧美日韩在线一二三| 视频一区二区三区不卡| 亚洲综合色成人| 国产又黄又猛视频| 国产成人免费av一区二区午夜| 精品国产乱码久久久久久浪潮| 免费看污黄网站在线观看| 天天射—综合中文网| 欧美激情综合亚洲一二区 | 日本特黄久久久高潮| 91最新在线免费观看| 天堂a中文在线| 最新中文字幕一区二区三区| 欧美亚洲精品一区二区| 久久精品嫩草影院| 亚洲国产成人在线视频| 九九这里只有精品视频| 一区二区高清| 91手机在线播放| 草草影院在线观看| 亚洲午夜一二三区视频| 91小视频网站| 亚洲亚洲免费| 欧美日韩第一页| 在线观看国产成人| 久久只精品国产| 国产成人一区二区三区别| 素人啪啪色综合| 日韩精品在线观| 免费一级全黄少妇性色生活片| 日韩中文字幕麻豆| 国产精品制服诱惑| 成人黄色网址| 欧美网站大全在线观看| av直播在线观看| 亚洲高清资源| 91影院在线免费观看视频| 久香视频在线观看| 精品免费在线观看| 久国产精品视频| 欧美一站二站| 国产成人精品av在线| 欧美一区二区三区黄片| 亚洲黄色av一区| 三区视频在线观看| 日本欧美肥老太交大片| 国产福利视频一区| 欧美男男同志| 岛国av午夜精品| 美女又爽又黄免费| 亚洲激情精品| 国产亚洲自拍偷拍| 毛片大全在线观看| 精品日韩99亚洲| 少妇影院在线观看| 国产成人在线观看免费网站| 欧美一级中文字幕| 日本在线一区二区三区| 九九久久国产精品| 国产ts变态重口人妖hd| 亚洲男人电影天堂| 中文字幕第三区| 欧美久久成人| 国产91aaa| 成人在线免费观看黄色| 亚洲成人教育av| 亚洲国产成人精品激情在线| 成人性视频免费网站| 日韩激情视频一区二区| 成人18夜夜网深夜福利网| 久久久久久久久久久国产| 亚洲av色香蕉一区二区三区| 亚洲综合成人在线| 在线看黄色的网站| 午夜亚洲激情| 亚洲巨乳在线观看| 国产精品久久久久久久久久辛辛| 欧美成人午夜激情视频| 黄色小视频免费在线观看| 五月激情综合网| 蜜桃精品一区二区| 美女性感视频久久| 黄色网络在线观看| 国内精品国产成人国产三级粉色| 97在线日本国产| 可以直接在线观看的av| 偷窥少妇高潮呻吟av久久免费| 久久精品免视看| 国产aⅴ精品一区二区三区色成熟| 国产亚洲综合在线| 欧美日韩一区二区三| 欧洲精品一区二区三区| 色婷婷成人综合| 国产成人精品一区二三区四区五区 | 国产精品1区2区在线观看| 懂色av中文在线| 欧美丰满高潮xxxx喷水动漫| 久久99久久久| 国产日韩一级二级三级| 亚洲av毛片在线观看| 一本久道久久综合婷婷鲸鱼| 亚洲成人av动漫| 91蜜桃臀久久一区二区| 日韩av高清不卡| 国产高清一区二区三区视频| 亚洲精品第一国产综合精品| 性高潮视频在线观看| 亚洲精品一二三区| brazzers精品成人一区| 国内欧美视频一区二区| 免费成人午夜视频| 91精品天堂福利在线观看| 精品久久精品久久| 91国产一区| 欧美在线日韩在线| 久久青青色综合| 中文字幕av一区| 欧洲精品久久一区二区| 欧美日韩成人一区| 天堂网免费视频| 亚洲一区二区三区中文字幕在线| 亚洲精品国产精品国自| av中文字幕一区| 青娱乐国产精品视频| 久久综合伊人| 人妻夜夜添夜夜无码av| 91精品秘密在线观看| 日韩电影在线播放| 久久综合五月婷婷| 亚洲精品欧美日韩专区| 韩国女主播一区二区| 韩国三级日本三级少妇99| 国产在线观看a视频| 在线观看精品国产视频| 无码精品人妻一区二区| 日韩女优毛片在线| 国产又粗又猛又爽又黄的视频一 | 卡一精品卡二卡三网站乱码| 91热精品视频| 国产精品天堂蜜av在线播放| 欧美中文在线免费| freexxx性亚洲精品| 欧美男插女视频| 国产成人在线视频免费观看| 中文字幕无线精品亚洲乱码一区| 国产在线你懂得| 精品夜色国产国偷在线| 日韩一级片免费看| 精品国产91亚洲一区二区三区婷婷 | 日韩三级免费| 欧美成人免费观看| free性欧美hd另类精品| 美女999久久久精品视频| 日韩精品黄色| www国产91| 黄色免费在线看| 久久久久www| 菠萝菠萝蜜在线视频免费观看| 另类天堂视频在线观看| 成a人片在线观看| 久久中文久久字幕| 婷婷丁香在线| 高清亚洲成在人网站天堂| 国内在线视频| 久久欧美在线电影| 国产资源在线观看入口av| 7m第一福利500精品视频| 2022成人影院| 国产精品视频999| 亚洲毛片在线免费| 7777精品久久久大香线蕉小说| 91精品麻豆| 国产福利久久| 亚洲三级性片| 特级西西444www大精品视频| 久久神马影院| 久久视频免费在线| 亚洲成人原创| 国产真实乱子伦| 美国十次了思思久久精品导航| 在线观看岛国av| 国产乱人伦偷精品视频免下载| 无码人妻aⅴ一区二区三区玉蒲团| gogogo免费视频观看亚洲一| 国产激情在线免费观看| 国产精品欧美极品| 欧美成人综合色| 欧美小视频在线观看| 一本色道久久综合亚洲| 日韩精品影音先锋| 婷婷丁香花五月天| 正在播放亚洲1区| 尤物在线网址| 555www成人网| 日韩护士脚交太爽了| 欧美日韩高清影院| 欧美激情乱人伦一区| 麻豆中文字幕在线观看| 国产一级免费观看| 日韩黄色三级| 国产午夜精品一区二区三区四区 | 3d动漫一区二区三区| 中文字幕一区2区3区| 久久精品亚洲成在人线av网址| 国产91对白在线观看九色| 精品视频在线播放免| 91精品国产99久久久久久红楼| 最近中文字幕在线mv视频在线 | 亚洲巨乳在线| 欧美成人aa大片| 黄色网zhan| 一区二区视频免费| 精品国产一区二区三区香蕉沈先生 | 男人天堂网在线视频| 亚洲免费电影在线观看| 国产黄色在线免费观看| 日韩美女视频中文字幕| 日韩欧美中文在线观看| 日本一区二区三区精品视频| 国自产拍偷拍福利精品免费一| 亚洲老女人av| av电影在线观看完整版一区二区| 永久免费看mv网站入口| 91黄色免费版| 视频国产一区二区三区| 欧美成人国产va精品日本一级| 二吊插入一穴一区二区| 精品一卡二卡三卡四卡日本乱码| 一本一本久久a久久综合精品| 欧美视频第一区| 成人福利视频网站| 男女性高潮免费网站| 欧美日韩精品免费观看视频 | 91成人精品在线| 一区二区在线观| 日本伊人午夜精品| 亚洲成人日韩在线| 亚洲成人免费观看| 精品国产九九九| 久久国产天堂福利天堂| 欧美一区=区三区| 亚洲一区二区在| 日本美女视频一区二区| 中文字幕国产专区| 欧美日韩色婷婷| 天天综合天天色| 久久久久久久久久久人体| 亚洲视频国产精品| 真人做人试看60分钟免费| 久久精品免费观看| 日本黄色激情视频| 欧美亚洲动漫制服丝袜| 国产人成在线观看| 国产福利视频一区二区| 国产亚洲欧美日韩在线观看一区二区| 国产亚洲综合视频| 久久久噜噜噜久久中文字幕色伊伊| 日韩无码精品一区二区三区| 亚洲精品国产美女| 天堂√8在线中文| 免费不卡亚洲欧美| 亚洲资源av| 美女被到爽高潮视频| 欧美午夜精品免费| 337p日本欧洲亚洲大胆鲁鲁| 国产精品入口夜色视频大尺度| 久久看人人摘| 中文字幕在线视频一区二区| 亚洲一级电影视频| 天堂在线免费av| 国产精品女人久久久久久| 国产精品久久天天影视| 红桃视频一区二区三区免费| 亚洲高清在线视频| 色在线免费视频| 国产精品入口免费视频一| 久久久久久久久久久妇女| av电影中文字幕| 精品女同一区二区三区在线播放| 黄色av网站在线免费观看| 国产欧美精品久久久| 伊人成综合网| 中文字幕在线播放视频| 日本韩国一区二区三区| 免费a在线看| 国产有色视频色综合| 日韩高清不卡一区二区三区| sm捆绑调教视频| 精品国产伦一区二区三区免费| 蜜桃视频www网站在线观看| 午夜精品短视频| 成人午夜免费av| 国产熟妇一区二区三区四区| 久久天天躁日日躁| 日韩精品免费一区二区三区竹菊| jizz欧美激情18| 亚洲最快最全在线视频| 你懂的免费在线观看视频网站| 成人在线一区二区| 亚洲深爱激情| 日韩一级片大全| 精品中文字幕久久久久久| 一级欧美视频| av免费播放网址| 亚洲色图丝袜美腿| 日韩欧美在线观看一区二区| 91亚洲一区精品| 日韩vs国产vs欧美| 日本三级中文字幕| www.xxxx精品| 九九在线高清精品视频|