国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費(fèi)電子書(shū)等14項(xiàng)超值服

開(kāi)通VIP
反射 — Java 高級(jí)開(kāi)發(fā)必須懂的

(給ImportNew加星標(biāo),提高Java技能)

轉(zhuǎn)自:博客園,作者:rocomp

鏈接:www.cnblogs.com/rocomp/p/4781987.html

理解反射對(duì)學(xué)習(xí)Java框架有很大的幫助,如Spring框架的核心就是使用Java反射實(shí)現(xiàn)的,而且對(duì)做一些Java底層的操作會(huì)很有幫助。 

一、Class類(lèi)的使用

1、萬(wàn)事萬(wàn)物皆對(duì)象,(當(dāng)然,基本數(shù)據(jù)類(lèi)型,靜態(tài)成員不是面向?qū)ο螅▽儆陬?lèi)的)),所以我們創(chuàng)建的每一個(gè)類(lèi)也都是對(duì)象,即類(lèi)本身是java.lang.Class類(lèi)的實(shí)例對(duì)象,但是這些對(duì)象都不需要new出來(lái),因?yàn)閖ava.lang.Class類(lèi)的構(gòu)造方法是私有的

2、任何一個(gè)類(lèi)都是Class類(lèi)的實(shí)例對(duì)象,這個(gè)實(shí)例對(duì)象有三種表示方式:(我們新建一個(gè)Student類(lèi))

  1. Class c1 = Student.class;//實(shí)際告訴我們?nèi)魏我粋€(gè)類(lèi)都有一個(gè)隱含的靜態(tài)成員變量class(知道類(lèi)名時(shí)用)

  2. Class c2 = stu.getClass();//已知該類(lèi)的對(duì)象通過(guò)getClass方法(知道對(duì)象時(shí)用)  

  3. Class c3 = Class.forName('類(lèi)的全名');//會(huì)有一個(gè)ClassNotFoundException異常

官網(wǎng)解釋說(shuō):c1,c2表示了Student類(lèi)的類(lèi)類(lèi)型()class type),萬(wàn)事萬(wàn)物皆對(duì)象,類(lèi)也是對(duì)象,是Class類(lèi)的實(shí)例對(duì)象,這個(gè)對(duì)象我們成為該類(lèi)的類(lèi)類(lèi)型(有點(diǎn)亂,但是慢慢捋一下還是能理解的)

這里有一點(diǎn)值得注意,當(dāng)我們執(zhí)行System.out.println(c1==c2);語(yǔ)句,結(jié)果返回的是true,這是為什么呢?原因是不管c1還是c2都代表了Student類(lèi)的類(lèi)類(lèi)型,一個(gè)類(lèi)可能是Class類(lèi)的一個(gè)實(shí)例對(duì)象。

我們完全可以通過(guò)類(lèi)的類(lèi)類(lèi)型創(chuàng)建該類(lèi)的對(duì)象實(shí)例,即通過(guò)c1或c2創(chuàng)建Student的實(shí)例。

Student stu = (Student)c1.newInstance();//前提是必須要有無(wú)參的構(gòu)造方法,因?yàn)樵撜Z(yǔ)句會(huì)去調(diào)用其無(wú)參構(gòu)造方法。該語(yǔ)句會(huì)拋出異常。

二、動(dòng)態(tài)加載類(lèi)

  1. 編譯時(shí)加載類(lèi)是靜態(tài)加載類(lèi),

    new 創(chuàng)建對(duì)象是靜態(tài)加載類(lèi),在編譯時(shí)刻就需要加載所有可用使用到的類(lèi),如果有一個(gè)用不了,那么整個(gè)文件都無(wú)法通過(guò)編譯

  2. 運(yùn)行時(shí)加載類(lèi)是動(dòng)態(tài)加載類(lèi)      

    Class c =  Class.forName('類(lèi)的全名'),不僅表示了類(lèi)的類(lèi)型,還表示了動(dòng)態(tài)加載類(lèi),編譯不會(huì)報(bào)錯(cuò),在運(yùn)行時(shí)才會(huì)加載,使用接口標(biāo)準(zhǔn)能更方便動(dòng)態(tài)加載類(lèi)的實(shí)現(xiàn)。功能性的類(lèi)盡量使用動(dòng)態(tài)加載,而不用靜態(tài)加載。

很多軟件比如QQ,360的在線(xiàn)升級(jí),并不需要重新編譯文件,只是動(dòng)態(tài)的加載新的東西

三、獲取方法信息

1、基本的數(shù)據(jù)類(lèi)型,void關(guān)鍵字都存在類(lèi)類(lèi)型

Class c1 =int.class;//int的類(lèi)類(lèi)型
Class c2 =String.class;//String類(lèi)的類(lèi)類(lèi)型,可以理解為編譯生成的那個(gè)String.class字節(jié)碼文件,
//當(dāng)然,這并不是官方的說(shuō)法
Class c3 =double.class;
Class c4 =Double.class;
Class c5 =void.class;

2、Class類(lèi)的基本API操作 

/**
* 打印類(lèi)的信息,包括類(lèi)的成員函數(shù),成員變量
* @param obj 該對(duì)象所屬類(lèi)的信息
*/

publicstaticvoid printClassMessage(Object obj){
//要獲取類(lèi)的信息,首先要獲取類(lèi)的類(lèi)類(lèi)型
Class c = obj.getClass();//傳遞的是哪個(gè)子類(lèi)的對(duì)象,c就是該子類(lèi)的類(lèi)類(lèi)型
//獲取類(lèi)的名稱(chēng)
System.out.println('累的名稱(chēng)是:' c.getName());

/*
* Method類(lèi),方法的對(duì)象
* 一個(gè)成員方法就是一個(gè)Method對(duì)象
* getMethods()方法獲取的是所有的public的函數(shù),包括父類(lèi)繼承而來(lái)的
* getDeclaredMethods()獲取的是多有該類(lèi)自己聲明的方法,不問(wèn)訪(fǎng)問(wèn)權(quán)限
*/

Method[] ms = c.getMethods();//c.getDeclaredMethods();
for(int i =0; i < ms.length; i ){
//得到方法的返回值類(lèi)型的類(lèi)類(lèi)型
Class retrunType = ms[i].getReturnType();
System.out.print(retrunType.getName() ' ');
//得到方法的名稱(chēng)
System.out.print(ms[i].getName() '(');
//獲取的參數(shù)類(lèi)型--->得到的是參數(shù)列表的類(lèi)型的類(lèi)類(lèi)型
Class[] paraTypes = ms[i].getParameterTypes();
for(Class class1 : paraTypes){
System.out.print(class1.getName() ',');
}
System.out.println(')');
}
}

Class的API中還有很多其他的方法,可以得到interface、Package、Annotation等很多信息,具體使用請(qǐng)參考幫助手冊(cè),本文就不在詳細(xì)講解。特別注意的一點(diǎn)是,如果你想得到一個(gè)類(lèi)的信息,首先就要獲取該類(lèi)的類(lèi)類(lèi)型。

四、獲取成員變量構(gòu)造函數(shù)信息  

/**
* 成員變量也是對(duì)象,是java.lang.reflect.Field這個(gè)類(lèi)的的對(duì)象
* Field類(lèi)封裝了關(guān)于成員變量的操作
* getFields()方法獲取的是所有public的成員變量的信息
* getDeclareFields()方法獲取的是該類(lèi)自己聲明的成員變量的信息
*/

Field[] fs = c.getDeclaredFields();
for(Field field : fs){
//得到成員變量的類(lèi)型的類(lèi)類(lèi)型
Class fieldType = field.getType();
String typeName = fieldType.getName();
//得到成員變量的名稱(chēng)
String fieldName = field.getName();
System.out.print(typeName ' ' fieldName);
}


/**
* 構(gòu)造函數(shù)也是對(duì)象
* java.lang.Constructor中封裝了構(gòu)造函數(shù)的信息
* getConstructor()方法獲取所有的public的構(gòu)造函數(shù)
* getDeclaredConstructors得到所有的構(gòu)造函數(shù)
*/

Constructor[] cs = c.getDeclaredConstructors();
for(Constructor constructor : cs){
System.out.print(constructor.getName() '(');
//獲取構(gòu)造函數(shù)的參數(shù)列表---》得到的是參數(shù)雷彪的類(lèi)類(lèi)型
Class[] paramTypes = constructor.getParameterTypes();
for(Class class1 : paramTypes){
System.out.print(class1.getName() ',');
}
System.out.println(')');
}

五、方法反射的基本操作

  1. 如何獲取某個(gè)方法

           方法的名稱(chēng)和方法的參數(shù)列表才能唯一決定某個(gè)方法

           Method m = c.getDeclaredMethod('方法名',可變參數(shù)列表(參數(shù)類(lèi)型.class))

  2. 方法的反射操作

           m.invoke(對(duì)象,參數(shù)列表)

           方法如果沒(méi)有返回值,返回null,如果有返回值返回Object類(lèi)型,然后再?gòu)?qiáng)制類(lèi)型轉(zhuǎn)換為原函數(shù)的返回值類(lèi)型

六、通過(guò)反射了解集合泛型的本質(zhì)

ArrayList list1 =newArrayList();
ArrayList<String> list2 =newArrayList<String>();

Class c1 = list1.getClass();
Class c2 = list2.getClass();

System.out.println(c1==c2);//結(jié)果為true,為什么??

結(jié)果分析:因?yàn)榉瓷涞牟僮鞫际蔷幾g之后的操作,也就是運(yùn)行時(shí)的操作,c1==c2返回true,說(shuō)明編譯之后集合的泛型是去泛型化的。

那么我們就可以理解為,Java集合中的泛型,是用于防止錯(cuò)誤類(lèi)型元素輸入的,比如在list2中我們add一個(gè)int,add(10)就會(huì)編譯報(bào)錯(cuò),那么這個(gè)泛型就可以只在編譯階段有效,通過(guò)了編譯階段,泛型就不存在了。可以驗(yàn)證,我們繞過(guò)編譯,用反射動(dòng)態(tài)的在list2中add一個(gè)int是可以成功的,只是這時(shí)因?yàn)閘ist2中存儲(chǔ)了多個(gè)不同類(lèi)型的數(shù)據(jù)(String型,和int型),就不能用for-each來(lái)遍歷了,會(huì)拋出類(lèi)型轉(zhuǎn)換錯(cuò)誤異常ClassCastException

補(bǔ)充資料:

七、關(guān)于Java類(lèi)加載器內(nèi)容的詳解

1、類(lèi)的加載

當(dāng)程序要使用某個(gè)類(lèi)時(shí),如果該類(lèi)還未被加載到內(nèi)存中,則系統(tǒng)會(huì)通過(guò)加載,連接,初始化三步來(lái)實(shí)現(xiàn)對(duì)這個(gè)類(lèi)進(jìn)行初始化

  • 加載:

           就是指將class文件讀入內(nèi)存,并為之創(chuàng)建一個(gè)Class對(duì)象,任何類(lèi)被使用時(shí)系統(tǒng)都會(huì)建立一個(gè)Class對(duì)象

  • 連接:

            驗(yàn)證:確保被加載類(lèi)的正確性

            準(zhǔn)備:負(fù)責(zé)為類(lèi)的靜態(tài)成員分配內(nèi)存,并設(shè)置默認(rèn)初始化值

            解析:將類(lèi)中的符號(hào)引用替換為直接引用

  • 初始化:

            局部變量保存在棧區(qū):必須手動(dòng)初始化

            new 的對(duì)象保存在堆區(qū):虛擬機(jī)會(huì)進(jìn)行默認(rèn)初始化,基本數(shù)據(jù)類(lèi)型初始化值為0,引用類(lèi)型初始化值為null

2、類(lèi)加載的時(shí)機(jī)(只加載一次)

以下時(shí)機(jī)僅表示第一次的時(shí)候

  1. 創(chuàng)建類(lèi)的實(shí)例的時(shí)候

  2. 訪(fǎng)問(wèn)類(lèi)的靜態(tài)變量的時(shí)候

  3. 調(diào)用類(lèi)的靜態(tài)方法的時(shí)候

  4. 使用反射方式來(lái)強(qiáng)制創(chuàng)建某個(gè)類(lèi)或接口對(duì)應(yīng)的java.lang.Class對(duì)象

  5. 初始化某個(gè)類(lèi)的子類(lèi)的時(shí)候

  6. 直接使用java.exe命令來(lái)運(yùn)行某個(gè)主類(lèi)

3、類(lèi)加載器

負(fù)責(zé)將.class文件加載到內(nèi)存中,并為之生成對(duì)應(yīng)的Class對(duì)象

雖然我們?cè)陂_(kāi)發(fā)過(guò)程中不需要關(guān)心類(lèi)加載機(jī)制,但是了解這個(gè)機(jī)制我們就能更好的理解程序的運(yùn)行

4、類(lèi)加載器的組成

  1. Bootstrap ClassLoader 根類(lèi)加載器

          也被稱(chēng)為引導(dǎo)類(lèi)加載器,負(fù)責(zé)Java核心類(lèi)的加載,比如System類(lèi),在JDK中JRE的lib目錄下rt.jar文件中的類(lèi)

  2. Extension ClassLoader 擴(kuò)展類(lèi)加載器

           負(fù)責(zé)JRE的擴(kuò)展目錄中jar包的加載,在JDK中JRE的lib目錄下ext目錄

  3. System ClassLoader 系統(tǒng)類(lèi)加載器

          負(fù)責(zé)在JVM啟動(dòng)時(shí)加載來(lái)自java命令的class文件,以及classpath環(huán)境變量所指定的jar包和類(lèi)路徑,主要是我們開(kāi)發(fā)者自己寫(xiě)的類(lèi)

本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶(hù)發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
不了解Java反射機(jī)制?看這篇就明白了!
JAVA開(kāi)發(fā):深入研究java.lang.Class類(lèi)
類(lèi)名.this與類(lèi)名.class
運(yùn)行時(shí)類(lèi)型識(shí)別——Class類(lèi)(動(dòng)態(tài)加載類(lèi))
第五章Java虛擬機(jī)(Chapter Five: The Java Virtual Mac...
Java面試題集(1-50)
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服