Java學(xué)習(xí)筆記:反射

類加載器

程序使用某個類時角钩,該類還未被加載到內(nèi)存
系統(tǒng)通過類加載冈敛、類連接贴唇、類初始化三步驟對類進(jìn)行初始化

類加載

  • 就是指將class文件讀入內(nèi)存丽柿,并為之創(chuàng)建一個java.lang.Class對象
  • 任何類被使用時,系統(tǒng)都會為之建立一個java.lang.Class對象

類的連接

  • 驗(yàn)證階段:用于檢驗(yàn)被加載的類是否有正確的內(nèi)部結(jié)構(gòu)蔗包,并和其他類協(xié)調(diào)一致
  • 準(zhǔn)備階段:負(fù)責(zé)為類的類變量分配內(nèi)存秉扑,并設(shè)置默認(rèn)初始化值
  • 解析階段:將類的二進(jìn)制數(shù)據(jù)中的符號引用替換為直接引用

類的初始化

  • 在該階段,主要就是對類變量進(jìn)行初始化

類的初始化步驟

  • 假如類還未被加載和連接,則程序先加載并連接該類
  • 假如該類的直接父類還未被初始化舟陆,則先初始化其直接父類
  • 假如類中有初始化語句误澳,則系統(tǒng)依次執(zhí)行這些初始化語句
  • ps:執(zhí)行第2個步驟,系統(tǒng)對直接父類初始化步驟也遵循初始化步驟1-3

類的初始化時機(jī)

  • 創(chuàng)建類的實(shí)例
  • 調(diào)用類的類方法
  • 訪問類或者接口的類變量秦躯,或者為該類變量賦值
  • 使用反射方式來強(qiáng)制創(chuàng)建某個類或接口對應(yīng)的java.lang.class
  • 初始化某個類的子類
  • 直接使用java.exe命令來運(yùn)行某個主類

類加載器

ClassLoader:是負(fù)責(zé)加載類的對象

Java運(yùn)行時具有以下內(nèi)置類加載器

  • Bootstrap class loader它是虛擬機(jī)的內(nèi)置類加載器忆谓,通常表示為null,并且無父null
  • Platform class loader平臺類加載器可以看到所有平臺類踱承,平臺類包括由平臺類加載器或其祖先定義的JavaSE平臺API倡缠,其實(shí)現(xiàn)類和JDK特定的運(yùn)行時類
  • System class loader它也被稱為應(yīng)用程序類加載器,與平臺類加載器不同茎活。系統(tǒng)類加載器通常用于定義應(yīng)用程序類路徑昙沦,模塊路徑的JDK特定工具上的類
  • 類加載器繼承關(guān)系
    System的父類加載器為Platform
    Platform的父類加載器為BootStrap

ClassLoader中的兩個方法

  • static ClassLoader getSystemClassLoader()返回用于委派的系統(tǒng)類加載器
  • ClassLoader getParent()返回父類加載器進(jìn)行委派
ClassLoader c=ClassLoader.getSystemClassLoader();
System.out.println(c);
ClassLoader c2=c.getParent();
System.out.println(c2);
ClassLoader c3=c2.getParent();
System.out.println(c3);

反射

反射概述

2021-02-10_141021.jpg

Java反射機(jī)制:指在運(yùn)行時去獲取一個類的變量和方法信息。然后通過獲取到的信息來創(chuàng)建對象妙色,調(diào)用方法的一種機(jī)制桅滋。這種動態(tài)性可以極大增強(qiáng)程序的靈活性,程序不用在編譯期就完成確定身辨,在運(yùn)行期仍可以擴(kuò)展

獲取Class類的對象

通過反射去使用一個類丐谋,首先要獲取該類的字節(jié)碼文件對象(類型為Class類型對象)
三種方式

  • 使用類的class屬性來獲取該類對應(yīng)的Class對象
    eg:Student.class將會返回Student類對應(yīng)的Class對象
  • 調(diào)用對象的getClass()方法,返回該對所屬類對應(yīng)的Class對象(所有Java對象都可)
  • 使用Class類中的靜態(tài)方法forName(String className)煌珊,要傳入字符串參數(shù)号俐,值是某個類的全路徑,也就是完整包名的路徑
//使用類的class屬性來獲取該類對應(yīng)的Class對象
Class<Student> c1=Student.class;
System.out.println(c1);
//調(diào)用對象的`getClass()`方法定庵,返回該對所屬類對應(yīng)的Class對象
Student s=new Student();
Class<? extends Student> c2=s.getClass();
System.out.println(c2);
//使用Class類中的靜態(tài)方法forName(String className)
Class<?> c3=Class.forName("com.itheima01.Student");
System.out.println(c3);

反射獲取構(gòu)造方法并使用

  • Constructor<?>[] getConstructors():返回所有公共構(gòu)造方法對象的數(shù)組
  • Constructor<?>[] getDeclaredConstructors():返回所有構(gòu)造方法對象的數(shù)組
  • Constructor<T> getConstructor(Class<?>...parameterTypes):返回單個公共構(gòu)造方法對象
  • Constructor<T> getDeclaredConstructor(Class<?>...parameterTypes):返回單個構(gòu)造方法對象
  • T newInstance(Object...initargs):根據(jù)指定的構(gòu)造方法創(chuàng)建對象
public class ReflectDemo01 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException
, IllegalAccessException, InvocationTargetException, InstantiationException {
        //獲取Class對象
        Class<?> c=Class.forName("com.itheima01.Student");
        //Constructor<?>[] getConstructors():返回所有公共構(gòu)造方法對象的數(shù)組
        Constructor<?>[] cons=c.getConstructors();
        for(Constructor con:cons){
            System.out.println(con);
        }
        //Constructor<?>[] getDeclaredConstructors():返回所有構(gòu)造方法對象的數(shù)組
        Constructor<?>[] cons1=c.getDeclaredConstructors();
        for(Constructor con:cons1){
            System.out.println(con);
        }
        //Constructor<T> getConstructor(Class<?>...parameterTypes):返回單個公共構(gòu)造方法對象
        //Constructor<T> getDeclaredConstructor(Class<?>...parameterTypes):返回單個構(gòu)造方法對象
        //參數(shù):你要獲取的構(gòu)造方法的參數(shù)個數(shù)和數(shù)據(jù)類型對應(yīng)的字節(jié)碼文件對象
        Constructor<?> con=c.getConstructor();
        //Constructor提供了一個類的單個構(gòu)造函數(shù)的信息和訪問權(quán)限
        /*T newInstance(Object...initargs)使用由此Constructor對象表示的構(gòu)造函數(shù)
          使用指的的初始化參數(shù)來創(chuàng)建和初始化構(gòu)造函數(shù)的聲明類的新實(shí)例*/
        Object obj=con.newInstance();
        System.out.println(obj);
    }
}

練習(xí)1

Class<?> c=Class.forName("com.itheima01.Student");
Constructor<?> con = c.getConstructor(String.class, int.class, String.class);
//基本數(shù)據(jù)類型也可以通過.class得到對應(yīng)的Class類型
Object obj=con.newInstance("林青霞",30,"西安");
System.out.println(obj);

練習(xí)2

Class<?> c=Class.forName("com.itheima01.Student");
Constructor<?> con = c.getDeclaredConstructor(String.class);
//暴力反射
//public void setAccessible(boolean flag):值為true,取消訪問檢查
con.setAccessible(true);
Object obj=con.newInstance("林青霞");
System.out.println(obj);

反射獲取成員變量并使用

  • Field[] getFields:返回所有公共成員變量對象的數(shù)組
  • Field[] getDeclaredFields:返回所有成員變量對象的數(shù)組
  • Field getField(String name):返回單個公共成員變量對象
  • Field getDeclaredField(String name):返回單個成員變量對象
  • void set(Object obj,Object value)
    將指定的對象參數(shù)中,由此Field對象表示的字段吏饿,設(shè)置為指定的新值
public class ReflectDemo04 {
    public static void main(String[] args) throws ....... {
        Class<?> c=Class.forName("com.itheima01.Student");
        //Field[] getFields:返回所有公共成員變量對象的數(shù)組
        //Field[] getDeclaredFields:返回所有成員變量對象的數(shù)組
        Field[] fields=c.getFields();
        Field[] fields1=c.getDeclaredFields();
        for(Field field:fields){
            System.out.println(field);
        }
        //Field getField(String name):返回單個公共成員變量對象
        //Field getDeclaredField(String name):返回單個成員變量對象
        Field addressField=c.getField("address");
        //獲取無參構(gòu)造方法創(chuàng)建對象
        Constructor<?> con=c.getConstructor();
        Object obj=con.newInstance();
        //Field提供有關(guān)類或接口的單個字段的信息的動態(tài)訪問
        addressField.set(obj,"西安");
        System.out.println(obj);
    }
}

練習(xí)

Class<?> c=Class.forName("com.itheima01.Student");
Constructor<?> con = c.getConstructor();
Object obj=con.newInstance();
System.out.println(obj);
//s.name="林青霞"
Field nameField=c.getDeclaredField("name");
nameField.setAccessible(true);
nameField.set(obj,"林青霞");
//s.age=20
Field ageField=c.getDeclaredField("age");
ageField.setAccessible(true);
ageField.set(obj,30);
//s.address="西安"
Field addressField=c.getDeclaredField("address");
addressField.setAccessible(true);
addressField.set(obj,"西安");
System.out.println(obj);

反射獲取成員方法并使用

  • Method[] getMethods():返回所有公共成員方法對象的數(shù)組,包括繼承的
  • Method[] getDeclaredMethods():返回所有成員方法對象的數(shù)組蔬浙,不包括繼承的
  • Method getMethod(String name,Class<?>...patameterTypes):返回單個公共成員方法對象
  • Method getDeclaredMethod(String name,Class<?>...parameterTypes):返回單個成員方法對象
  • Object invoke(Object obj,Object...args):在具有指定參數(shù)的指定對象上調(diào)用此方法對象表示的基礎(chǔ)方法
public class ReflectDemo06 {
    public static void main(String[] args) throws ......{
        Class<?> c=Class.forName("com.itheima01.Student");
        //Method[] getMethods():返回所有公共成員方法對象的數(shù)組猪落,包括繼承的
        //Method[] getDeclaredMethods():返回所有成員方法對象的數(shù)組,不包括繼承的
        Method[] methods=c.getMethods();
        for(Method method:methods){
            System.out.println(method);
        }
        //Method getMethod(String name,Class<?>...patameterTypes):返回單個公共成員方法對象
        //Method getDeclaredMethod(String name,Class<?>...parameterTypes):返回單個成員方法對象
        Method m = c.getMethod("method1");
        //獲取無參構(gòu)造方法創(chuàng)造對象
        Constructor<?> con=c.getConstructor();
        Object obj=con.newInstance();
    //Object invoke(Object obj,Object...args):在具有指定參數(shù)的指定對象上調(diào)用此方法對象表示的基礎(chǔ)方法
        //Object:返回值類型畴博;obj:調(diào)用方法的對象笨忌;args:方法需要的參數(shù);
        m.invoke(obj);
    }
}

練習(xí)

Class<?> c=Class.forName("com.itheima01.Student");
//Student s=new Student();
Constructor<?> con=c.getConstructor();
Object obj=con.newInstance();
//s.method1();
Method m1 = c.getMethod("method1");
m1.invoke(obj);
//s.method2("林青霞")
Method m2 = c.getMethod("Method2", String.class);
m2.invoke(obj,"林青霞");
//String ss=s.method3("林青霞",30);System.out.println(ss)
Method m3 = c.getMethod("method3", String.class, int.class);
Object o = m3.invoke("林青霞", 30);
System.out.println(o);
//s.function();
Method m4 = c.getDeclaredMethod("function");
m4.setAccessible(true);
m4.invoke(obj);

反射練習(xí)

越過泛型檢查
有一個ArrayList<Integer>集合俱病,在這個集合中添加一個字符串?dāng)?shù)據(jù)官疲,實(shí)現(xiàn)如下
(正常情況字符串無法添加到Integer類型集合中)

public class ReflectTest01 {
    public static void main(String[] args) throws ...... {
        //創(chuàng)建集合
        ArrayList<Integer> array=new ArrayList<>();
        Class<? extends ArrayList> c=array.getClass();
        //反射可以越過泛型檢查,獲取原始方法所需要參數(shù)類型
        Method m = c.getMethod("add", Object.class);
        m.invoke(array,"hello");
        m.invoke(array,"world");
        m.invoke(array,"java");
        System.out.println(array);
    }
}

運(yùn)行配置文件指定內(nèi)容

//class.txt文件
className=com.itheima03.Student
methodName=study
//Student類
public class Student {
    public void study(){
        System.out.println("好好學(xué)習(xí)亮隙,天天向上");
    }
}
//反射測試
public class ReflectTest02 {
    public static void main(String[] args) throws ...... {
        /*class.txt
          className=xxx
          methodName=xxx */
        //加載數(shù)據(jù)
        Properties prop=new Properties();
        FileReader fr=new FileReader("myReflect\\class.txt");
        prop.load(fr);
        fr.close();
        /*  已獲得數(shù)據(jù)
            className=com.itheima03.Student
            methodName=study
         */
        String className=prop.getProperty("className");
        String methodName=prop.getProperty("methodName");
        //通過反射來使用
        Class<?> c=Class.forName(className);
        Constructor<?> con=c.getConstructor();
        Object obj=con.newInstance();
        Method m = c.getMethod(methodName);
        m.invoke(obj);
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末途凫,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子溢吻,更是在濱河造成了極大的恐慌维费,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,816評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異犀盟,居然都是意外死亡噪漾,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,729評論 3 385
  • 文/潘曉璐 我一進(jìn)店門且蓬,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人题翰,你說我怎么就攤上這事恶阴。” “怎么了豹障?”我有些...
    開封第一講書人閱讀 158,300評論 0 348
  • 文/不壞的土叔 我叫張陵冯事,是天一觀的道長。 經(jīng)常有香客問我血公,道長昵仅,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,780評論 1 285
  • 正文 為了忘掉前任累魔,我火速辦了婚禮摔笤,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘垦写。我一直安慰自己吕世,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,890評論 6 385
  • 文/花漫 我一把揭開白布梯投。 她就那樣靜靜地躺著命辖,像睡著了一般。 火紅的嫁衣襯著肌膚如雪分蓖。 梳的紋絲不亂的頭發(fā)上尔艇,一...
    開封第一講書人閱讀 50,084評論 1 291
  • 那天,我揣著相機(jī)與錄音么鹤,去河邊找鬼终娃。 笑死,一個胖子當(dāng)著我的面吹牛午磁,可吹牛的內(nèi)容都是我干的尝抖。 我是一名探鬼主播,決...
    沈念sama閱讀 39,151評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼迅皇,長吁一口氣:“原來是場噩夢啊……” “哼昧辽!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起登颓,我...
    開封第一講書人閱讀 37,912評論 0 268
  • 序言:老撾萬榮一對情侶失蹤搅荞,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體咕痛,經(jīng)...
    沈念sama閱讀 44,355評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡痢甘,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,666評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了茉贡。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片塞栅。...
    茶點(diǎn)故事閱讀 38,809評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖腔丧,靈堂內(nèi)的尸體忽然破棺而出放椰,到底是詐尸還是另有隱情,我是刑警寧澤愉粤,帶...
    沈念sama閱讀 34,504評論 4 334
  • 正文 年R本政府宣布砾医,位于F島的核電站,受9級特大地震影響衣厘,放射性物質(zhì)發(fā)生泄漏如蚜。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,150評論 3 317
  • 文/蒙蒙 一影暴、第九天 我趴在偏房一處隱蔽的房頂上張望错邦。 院中可真熱鬧,春花似錦坤检、人聲如沸兴猩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽倾芝。三九已至,卻和暖如春箭跳,著一層夾襖步出監(jiān)牢的瞬間诸蚕,已是汗流浹背冠场。 一陣腳步聲響...
    開封第一講書人閱讀 32,121評論 1 267
  • 我被黑心中介騙來泰國打工怀泊, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留国旷,地道東北人。 一個月前我還...
    沈念sama閱讀 46,628評論 2 362
  • 正文 我出身青樓屉来,卻偏偏與公主長得像路翻,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子茄靠,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,724評論 2 351

推薦閱讀更多精彩內(nèi)容