国产成人精品久久免费动漫-国产成人精品天堂-国产成人精品区在线观看-国产成人精品日本-a级毛片无码免费真人-a级毛片毛片免费观看久潮喷

您的位置:首頁技術(shù)文章
文章詳情頁

JAVA中的糕富帥技術(shù)——反射(一)

瀏覽:2日期:2022-09-06 16:13:03

 今天就來談?wù)劮瓷錂C(jī)制;學(xué)過JAVA的人不一定懂得反射,但是一定聽說過反射,不過也僅僅是聽說過而已;因?yàn)榉瓷溆玫牡胤揭膊粫敲炊啵欠瓷溆玫拿罱?jīng)常會解決我們撓破頭皮的大問題。至于諸如為什么叫做反射、而不叫做正射倒射此類的歷史問題,還是交給歷史學(xué)家去研究吧。。。

反射的基石

在談反射之前,我們應(yīng)該先了解下類的概念來引入。類是一種抽象的概念,舉個(gè)例子“我爸是李剛我爸李雙江”,從這句話中我們發(fā)現(xiàn)有李剛、李雙江這兩個(gè)人,我們來抽象它們的特點(diǎn),我們發(fā)現(xiàn)它們都像人。沒錯,那么我們就可以將人作為它們的一個(gè)抽象,反過來說李剛和李雙江就是人的一個(gè)具體實(shí)例;所以我們可以用一個(gè)Person類代表人來表示這種抽象。既然理解了類的概念,那些年那些陪我們度過日日夜夜的java類們,我們是不是也應(yīng)該抽象出一個(gè)類來證明一下他們,沒錯,那就是Class了!

Class就是java類的抽象,它抽象出了java的共性,如類的名字、類的構(gòu)造方法、類的成員變量、類的老爸、類的方法等等等。既然這么說,那么我們通過這個(gè)Class,我們就可以得到這個(gè)類的方方面面的信息、興許還能比查戶口還詳細(xì)呢。我們創(chuàng)建出的每一個(gè)類,例如person類,說到底也就是我們實(shí)例化了一個(gè)Class的實(shí)例,來保存person類的名字、變量、方法這些信息,在內(nèi)存中表示就是保存了person類的字節(jié)碼,如果你理解了這些并且接受了我的看法,那么咱們有共同語言,可以繼續(xù)往下說。

既然person類有擁有自己的字節(jié)碼,那么我們可以獲取到這個(gè)字節(jié)碼嗎?答案是肯定的,而且還不止一種方法。參見代碼:

public static void main(String[] args) throws Exception {//第一種方法,直接通過Person類來獲取字節(jié)碼 Class cls1 = Person.class;//第二種方法,通過類的實(shí)例來獲取Person類的字節(jié)碼 Person person = new Person();Class cls2 = person.getClass();//第三種方法,調(diào)用Class類的靜態(tài)方法來獲取對應(yīng)類的字節(jié)碼,該方法會拋出異常 Class cls3 = Class.forName('Person');}

從代碼中看,我們可以斷定:Person類的字節(jié)碼就是Class的具體實(shí)例;我們也可以猜到,至于類的字節(jié)碼有包含什么東東,大家盡管猜吧,后面我會慢慢講解。我們再來看看下面的代碼:

System.out.println(cls1 == cls2);System.out.println(cls2 == cls3);

我們運(yùn)行程序,會發(fā)現(xiàn)輸出了:

truetrue

這三個(gè)玩意竟然是同一個(gè)東西,那么就很好解釋了:在java的虛擬機(jī)中,每一個(gè)類都會被保存成為一個(gè)字節(jié)碼,用來保存該類的信息如名字、父類、變量、方法等。一個(gè)類的字節(jié)碼在虛擬機(jī)中有且只有一個(gè),也就是在第一次加載該類的時(shí)候會將類的字節(jié)碼加載到j(luò)ava虛擬機(jī)中,而上面有三種方法可以從虛擬機(jī)中獲取類的字節(jié)碼(PS:第三種方法最為常用),但是你別疑惑獲取這個(gè)字節(jié)碼干嘛嘛用,我們要反射嘛,說白了我們就是要來強(qiáng)暴這字節(jié)碼(Class)。。。。。(~ o ~)~zZ

理解反射

既然前面講解了Class類,現(xiàn)在我們可以開始講反射了。反射是什么呢?反射就是將類的各種成分映射成各種類,我們知道一個(gè)java類可以用一個(gè)class的對象來表示,這個(gè)類的組成成分有名字、變量、構(gòu)造方法等信息,我們當(dāng)然可以用一個(gè)個(gè)java類的表示。換句話說,表示java類的Class類提供了一系列的方法給我們用來獲取其中的變量、方法、構(gòu)造方法等信息,這些信息也有相應(yīng)的類的實(shí)例來表示,也就是Field、Method、Constructor等等。或者更通俗的說,F(xiàn)ield就是java類中的所有變量的抽象、同理Method就是java類中所有方法的抽象,如果還是看不懂,很正常,往下看代碼估計(jì)更好理解。

構(gòu)造方法的反射

從前面我們知道,Constructor就是java類所有構(gòu)造方法的抽象。那么我們怎么通過反射來獲取類的構(gòu)造方法呢,參見代碼:

public class Test{ public static void main(String[] args) throws Exception {Class cls = Person.class;//獲取Person類的字節(jié)碼 Constructor constructor1 = cls.getConstructor();//調(diào)用getConstructor()獲取Person無參構(gòu)造方法 Person p1 = (Person) constructor1.newInstance();//通過調(diào)用newInstance()來執(zhí)行無參構(gòu)造方法 Constructor constructor2 = cls.getConstructor(int.class);//調(diào)用getConstructor(*.class)獲取Person帶參構(gòu)造方法 Person p2 = (Person) constructor2.newInstance(1);//通過調(diào)用newInstance(int)來執(zhí)行帶參構(gòu)造方法 }} class Person{ public Person(){System.out.println('無參構(gòu)造方法');} public Person(int i){System.out.println('帶參構(gòu)造方法');}}

控制臺輸出:

無參構(gòu)造方法帶參構(gòu)造方法

這里我們開始講解一下,代碼通過Person.class來獲取Person類的字節(jié)碼并將其保存在一個(gè)Class類的實(shí)例cls中,然后再通過cls.getConstructor()來獲取字節(jié)碼中的構(gòu)造方法并將其放入Constructor的實(shí)例constructor之中,很明顯,這個(gè)constructor并不是Person的構(gòu)造方法,而是保存Person構(gòu)造方法的一個(gè)實(shí)例,所以我們可以通過調(diào)用newInstance()來獲取保存在constructor中的person類的構(gòu)造方法并執(zhí)行,構(gòu)造方法執(zhí)行并返回一個(gè)Object的實(shí)例,并將其強(qiáng)轉(zhuǎn)為Person并保存在person的變量中,這就是調(diào)用反射來獲取構(gòu)造方法生成實(shí)例的全過程。

在代碼中,我們也可以知道怎么獲取帶參的構(gòu)造方法,這是我們需要在getConstructor()是傳入構(gòu)造方法對應(yīng)參數(shù)的字節(jié)碼,例如代碼中Person(int i)我們需要傳入一個(gè)int.class(或者是Integet.TYPE)的字節(jié)碼提供給Class定位需要獲取的構(gòu)造方法。但是如果你比較貪心想獲取全部的構(gòu)造方法,沒問題,通過getConstructors():

Class cls = Person.class;//獲取Person類的字節(jié)碼 Constructor[] constructors = cls.getConstructors();//調(diào)用getConstructor()獲取Person無參構(gòu)造方法 for(Constructor c : constructors){//Person p = c.newInstance(****);遍歷執(zhí)行構(gòu)造方法 }

然后通過for循環(huán),就可以處理你所需要的構(gòu)造方法了。

成員變量的反射

我們說完了構(gòu)造方法的反射,我們就接下來談?wù)劤蓡T變量的反射的用法。慣例還是先看代碼:

public class Test{ public static void main(String[] args) throws Exception {Person p = new Person('小紅', 20);Class cls = Class.forName('com.net168.test.Person');Field fieldName = cls.getField('name'); //fieldNmae的值是小紅嗎?錯!它只是代表Person類身上name的這個(gè)變量,并沒有對應(yīng)到對象身上 // System.out.println(fieldNmae); //fieldNmae不代表具體的值,只代表一個(gè)變量,所以我們需要傳入一個(gè)person實(shí)例才能獲取到其對應(yīng)的值 System.out.println(fieldName.get(p)); }} class Person{ public Person(String name, int age){ this.name = name; this.age = age; } public String name; private int age;//對于某些人來說,年齡是秘密! }

跟構(gòu)造方法的反射的實(shí)現(xiàn)差不多,我們也是先通過獲取Person的字節(jié)碼cls,然后從其中將Person的成員變量映射成一個(gè)Field類,在這里我們將Person.name這個(gè)變量映射成fieldName這個(gè)對象,當(dāng)然我們不可能單純的從fieldName這個(gè)對象中獲取咱們的“小紅”,因?yàn)閒ieldName是從cls中獲取的而并不是從person的實(shí)例中獲取的,所以它值并不是小紅;而是我們可以通過小紅這個(gè)person的實(shí)例p與fieldName聯(lián)系起來,也就是調(diào)用fieldName.get(p)才能獲取小紅這個(gè)字符串。

但是我們?nèi)绻氆@取小紅年齡呢,女人的年齡大多是秘密,私有變量我們也可以這樣獲取嗎?修改下代碼:

Person p = new Person('小紅', 20);Class cls = Class.forName('com.net168.test.Person');Field fieldAge = cls.getField('age');System.out.println(fieldAge.get(p));

執(zhí)行結(jié)果是:

Exception in thread 'main' java.lang.NoSuchFieldException: ageat java.lang.Class.getField(Unknown Source)at com.net168.test.Test.main(Test.java:11)

沒有這個(gè)字段,明明是有這個(gè)age的字段呀!但是我們發(fā)現(xiàn),原來這個(gè)女生的年齡是私有的,她就是不肯告訴咱們啊,那怎么辦?她不想告訴我們,我們就沒法知道了嗎?屌絲是不會那么容易屈服的!所以我們可以稍作一點(diǎn)處理,如下:

Person p = new Person('小紅', 20);Class cls = Class.forName('com.net168.test.Person');Field fieldAge = cls.getDeclaredField('age');//獲取類的私有變量 fieldAge.setAccessible(true);//設(shè)置該私有變量可被外面訪問 System.out.println(fieldAge.get(p));

可以通過getDeclaredField()來獲取Person類的私有變量,而且我們還可以在獲取到外界看不到的私有變量后,再通過setAccessible(true)設(shè)置該私有變量可以被強(qiáng)制訪問。暴力吧,JAVA的反射也被有些人叫做暴力反射。。。運(yùn)行代碼,我們就知道了小紅的芳齡 了:20

成員方法的反射

如果大家看懂了前面成員變量和構(gòu)造方法的反射,基本上再了解成員方法的反射就沒有什么困難了,不賣關(guān)子,還是先上下代碼:

public class Test{ public static void main(String[] args) throws Exception {Person p = new Person();Class cls = p.getClass();//獲取Person的字節(jié)碼 //獲取setName()方法,需要傳入?yún)?shù)為String Method method1 = cls.getMethod('setName', String.class);method1.invoke(p, '小明');//關(guān)聯(lián)p,輸入“小明”并執(zhí)行該方法 //獲取getName()方法,無參則設(shè)為null Method method2 = cls.getMethod('getName', null);String name = (String) method2.invoke(p, null);//invoke返回的類型為Object System.out.println(name); //獲取靜態(tài)方法,由于靜態(tài)方法只依賴與類,所以不需要提供具體的實(shí)例 Method method3 = cls.getMethod('show', int.class); // method3.invoke(p, 1);提供具體實(shí)例p也可通過編譯 method3.invoke(null, 1); }} class Person{ public String name; public String getName(){ return name; } public void setName(String name){ this.name = name;System.out.println('設(shè)置name值為:' + name); } public static void show(int i){System.out.println('這是一個(gè)靜態(tài)方法:' + i); }}

程序運(yùn)行結(jié)果:

設(shè)置name值為:小明小明這是一個(gè)靜態(tài)方法:1

在方法的反射中,我們是利用了Method這個(gè)類,由于跟構(gòu)造方法類似,所以我不就再就獲取有參無參的方法的不同之處進(jìn)行講解。總體來說,就是通過Person的字節(jié)碼獲取到Person類中對應(yīng)的方法并將其保存到Method的一個(gè)對象中,然后通過這個(gè)對象跟Person的具體實(shí)例進(jìn)行搭配,通過invoke()就可以調(diào)用到具體實(shí)例的對應(yīng)方法。在這里我們需要注意的時(shí)靜態(tài)方法的反射,由于靜態(tài)方法屬于一個(gè)類并不是屬于特定的一個(gè)對象,所以我們在調(diào)用靜態(tài)方法的invoke()時(shí),并不需要傳入一個(gè)對象,當(dāng)然你非要傳入一個(gè)具體的實(shí)例也是沒有關(guān)系的,答案依然正確。

標(biāo)簽: Java
相關(guān)文章:
主站蜘蛛池模板: 99在线观看视频免费 | 亚洲欧美一二三区 | 国产成人永久免费视频 | 一级做人爱a视频正版免费 一级做性色a爱片久久片 | 精品视频一区二区三区 | 久久免费国产精品一区二区 | 白嫩美女一级毛片免费看 | 亚洲精品国产第一区二区多人 | 国产精选经典三级小泽玛利亚 | 99ri在线观看 | 中国黄色网址大全 | 亚洲精品综合 | 欧美xxxxx九色视频免费观看 | 欧美亚洲欧美区 | 成在线人免费视频 | 一区二区三区在线播放视频 | 日本一级特黄特色大片免费视频 | 在线观看精品视频网站www | 99久久精品国产片 | 亚洲第四页 | 色老头一区二区三区在线观看 | 欧美日本一道高清二区三区 | 欧美老头老太做爰xxxx | 怡红院在线视频全部观看 | 欧美高清色视频在线播放 | 亚洲日本在线观看网址 | japanese色系国产在线高清 | 精品免费久久久久国产一区 | 久久精品视频99精品视频150 | 亚洲国产精品自产拍在线播放 | 久久精品99毛片免费 | 欧美另类孕交免费观看 | 大学生一级一片第一次免费 | 99久久99热精品免费观看国产 | 免费看美女无遮掩的软件 | 国产精选一区二区 | 99久久精品费精品国产一区二区 | 久久99久久精品视频 | 香蕉久| 久久精品视频1 | 经典香港一级a毛片免费看 精品400部自拍视频在线播放 |