新鮮出爐,深入講解java反射的底層原理,這篇算講的不錯(cuò)了!

反射

  1. 反射

Java代碼和Java文件

Java代碼基本格式
    1. Java代碼都在類(lèi)內(nèi)或者接口內(nèi)
    2. 
        class 類(lèi)名 {
            成員變量
            構(gòu)造方法
            成員方法
            Annotation 注解
        }

Java文件要求:
    1. 通常情況下一個(gè)Java文件對(duì)應(yīng)一個(gè)Java類(lèi)
    2. Java文件包含當(dāng)前Java代碼的所有內(nèi)容?。?!

Java文件和.class字節(jié)碼文件

Java文件
    FirstJava.java
    通過(guò)編譯器 javac ==> javac FirstJava.java ==> FirstJava.class

.class字節(jié)碼文件是什么???
    二進(jìn)制可執(zhí)行文件。
    .class字節(jié)碼文件中會(huì)包含Java文件的所有內(nèi)容。
    .class字節(jié)碼文件包含Java程序的所有可執(zhí)行內(nèi)容(注釋不參與編譯和執(zhí)行)。

class字節(jié)碼文件在內(nèi)存中的位置

class字節(jié)碼文件和Java代碼關(guān)系

Class類(lèi)相關(guān)方法

Class Class.forName(String packageNameAndClassName) throws ClassNotFoundException;
    根據(jù)完整的包名.類(lèi)名獲取對(duì)應(yīng)的Class類(lèi)對(duì)象
    ClassNotFoundException 未找到指定類(lèi)

Class 類(lèi)對(duì)象.getClass();
    通過(guò)類(lèi)對(duì)象獲取當(dāng)前類(lèi)對(duì)象對(duì)應(yīng)的Class類(lèi)對(duì)象
    例如:
        Person p = new Person();  p.getClass() ==> Person類(lèi)對(duì)應(yīng)Class對(duì)象

Class 類(lèi)名.class;
    通過(guò)類(lèi)名獲取當(dāng)前類(lèi)對(duì)應(yīng)屬性 Class對(duì)象
    例如: 
        Person.class ==> Person類(lèi)對(duì)應(yīng)Class對(duì)象。
        


package com.qfedu.a_reflect;

/**
 * Class類(lèi)方法演示
 * 
 * @author 期年之前ying@
 *
 */
public class GetClassObject {
    public static void main(String[] args) throws ClassNotFoundException {
        /*
         * Class Class.forName(String packageNameAndClassName) 
         *          throws ClassNotFoundException;
         */
        Class cls1 = Class.forName("com.project.a_reflect.Person");
        
        /*
         * Class 類(lèi)對(duì)象.getClass();
         */
        Person person = new Person();
        Class cls2 = person.getClass();
        
        /*
         * Class 類(lèi)名.class;
         */
        Class cls3 = Person.class;
        
        /*
         
         *      不管是通過(guò)哪一種方式獲取指定類(lèi)的Class對(duì)象,都是同一個(gè)Class對(duì)象
         * 因?yàn)楫?dāng)前Person類(lèi)在當(dāng)前程序中有且只占用一次代碼區(qū)空間。
         */
        System.out.println("cls1 == cls2 : " + (cls1 == cls2));
        System.out.println("cls2 == cls3 : " + (cls2 == cls3));
        System.out.println("cls3 == cls1 : " + (cls3 == cls1));
    }
}

操作Constructor 構(gòu)造方法類(lèi)

通過(guò)Class類(lèi)對(duì)象獲取對(duì)應(yīng)類(lèi)的Constructor構(gòu)造方法類(lèi)對(duì)象

Constructor[] getConstructors();
    獲取當(dāng)前Class對(duì)象對(duì)應(yīng)類(lèi)中所有非私有化構(gòu)造方法類(lèi)對(duì)象數(shù)組。
    
Constructor[] getDeclaredConstructors();
    【暴力反射】
    獲取當(dāng)前Class對(duì)象對(duì)應(yīng)類(lèi)中的所有構(gòu)造方法類(lèi)對(duì)象數(shù)組,包括私有化構(gòu)造方法。
    
Constructor getConstructor(Class... parameterTypes);
    獲取當(dāng)前Class對(duì)象中,指定參數(shù)數(shù)據(jù)類(lèi)型的構(gòu)造方法。獲取的構(gòu)造方法為非私有化構(gòu)造方法
    Class... parameterTypes 
        Class類(lèi)型不定長(zhǎng)參數(shù),用于約束當(dāng)前構(gòu)造方法對(duì)應(yīng)的數(shù)據(jù)類(lèi)型。
    例如:
        無(wú)參數(shù)構(gòu)造方法
        cls.getConstructor(); ==> Person();
        兩個(gè)參數(shù)構(gòu)造方法(int, String)
        cls.getConstructor(int.class, String.class) ==> Person(int, String)
        
Constructor getDeclaredConstructor(Class... parameterTypes);
    【暴力反射】
    獲取當(dāng)前Class對(duì)象中,指定數(shù)據(jù)類(lèi)型的構(gòu)造方法,包括私有化構(gòu)造方法
    例如:
        獲取私有化String類(lèi)型構(gòu)造方法
        cls.getDeclaredConstructor(String.class) ==> private Person(String.class)

操作Constructor類(lèi)對(duì)象創(chuàng)建對(duì)應(yīng)類(lèi)對(duì)象

Object newInstance(Object... parameters);
    通過(guò)Constructor類(lèi)對(duì)象,執(zhí)行對(duì)應(yīng)的構(gòu)造方法,創(chuàng)建對(duì)應(yīng)類(lèi)對(duì)象
    Object... 不定長(zhǎng)參數(shù),要求數(shù)據(jù)類(lèi)型為Object類(lèi)型。
    例如:
        Person(); 無(wú)參數(shù)構(gòu)造方法
        Person p1 = (Person) constructor.newInstance();
        Person(int, java.lang.String);
        Person p2 = (Person) constructor.newInstance(10, "Java真好學(xué)"); 

package com.qfedu.a_reflect;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

/**
 * 操作Constructor構(gòu)造方法類(lèi)對(duì)象
 * 
 * @author 期年之前ying@
 *
 */
public class GetConstructorObject {
    public static void main(String[] args) 
            throws ClassNotFoundException, NoSuchMethodException, SecurityException, 
            InstantiationException, IllegalAccessException, IllegalArgumentException, 
            InvocationTargetException {
        /*
         * Class Class.forName(String packageNameAndClassName) 
         *          throws ClassNotFoundException;
         */
        Class cls = Class.forName("com.project.a_reflect.Person");
        
        /*
         * 1. 獲取當(dāng)前Class對(duì)象對(duì)應(yīng)類(lèi)中所有非私有化構(gòu)造方法類(lèi)對(duì)象數(shù)組
         */
        Constructor[] constructors = cls.getConstructors();
        for (Constructor constructor : constructors) {
            System.out.println(constructor);
        }
        
        System.out.println();
        
        /*
         * 2. 【暴力反射】
         * 獲取當(dāng)前Class對(duì)象對(duì)應(yīng)類(lèi)中的所有構(gòu)造方法類(lèi)對(duì)象數(shù)組,包括私有化構(gòu)造方法。
         */
        Constructor[] declaredConstructors = cls.getDeclaredConstructors();
        for (Constructor constructor : declaredConstructors) {
            System.out.println(constructor);
        }
        
        System.out.println();
        
        /*
         * 3. 獲取當(dāng)前Class對(duì)象中,指定參數(shù)數(shù)據(jù)類(lèi)型的構(gòu)造方法。獲取的構(gòu)造方法為非私有化構(gòu)造方法
         */
        Constructor constructor1 = cls.getConstructor();
        Constructor constructor2 = cls.getConstructor(int.class);
        Constructor constructor3 = cls.getConstructor(int.class, String.class);
        System.out.println(constructor1);
        System.out.println(constructor2);
        System.out.println(constructor3);
        
        /*
         * 4. 【暴力反射】    
         *  獲取當(dāng)前Class對(duì)象中,指定數(shù)據(jù)類(lèi)型的構(gòu)造方法,包括私有化構(gòu)造方法
         */
        Constructor constructor4 = cls.getDeclaredConstructor(String.class);
        System.out.println(constructor4);
        
        System.out.println();
        /*
         * newInstance 創(chuàng)建類(lèi)對(duì)象
         */
        Person p1 = (Person) constructor1.newInstance();
        Person p2 = (Person) constructor2.newInstance(10);
        Person p3 = (Person) constructor3.newInstance(20, "張三愛(ài)Java");
        System.out.println(p1);
        System.out.println(p2);
        System.out.println(p3);
        
        /*
         * 給予暴力反射操作使用權(quán)限!??!
         * setAccessible(boolean flag);
         */
        constructor4.setAccessible(true);
        Person p4 = (Person) constructor4.newInstance("Java快樂(lè)多");
        System.out.println(p4);
    }
}

操作 Method 成員方法類(lèi)

通過(guò)Class類(lèi)對(duì)象獲取對(duì)應(yīng)類(lèi)的Method成員方法類(lèi)對(duì)象

Method[] getMethods();
    通過(guò)Class類(lèi)對(duì)象調(diào)用,獲取當(dāng)前類(lèi)內(nèi)的所有非私有化成員方法,包含從父類(lèi)繼承而來(lái)子類(lèi)可以使用的非私有化方法。
    
Method[] getDeclaredMethods();
    【暴力反射】
    通過(guò)Class類(lèi)對(duì)象調(diào)用,獲取當(dāng)前類(lèi)內(nèi)的所有成員方法,包括私有化成員方法,但是不包括從父類(lèi)繼承而來(lái)的方法。
    
Method getMethod(String methodName, Class... parameterTypes);
    通過(guò)Class類(lèi)對(duì)象調(diào)用,根據(jù)方法名稱(chēng)和對(duì)應(yīng)的形式參數(shù)列表數(shù)據(jù)類(lèi)型獲取對(duì)應(yīng)的成員方法,可以獲取父類(lèi)繼承方法,不能獲取私有化成員方法
    例如:
        無(wú)參數(shù)成員方法 獲取 game();
            cls.getMethod("game");
        有參數(shù)成員方法 獲取 game(String);
            cls.getMethod("game", String.class);
    
Method getDeclaredMethod(String methodName, Class... parameterTypes);
    通過(guò)Class類(lèi)對(duì)象調(diào)用,根據(jù)方法名稱(chēng)和對(duì)應(yīng)的形式參數(shù)列表數(shù)據(jù)類(lèi)型獲取對(duì)應(yīng)的成員方法,可以獲取私有化成員方法,不能獲取父類(lèi)成員方法。
    例如:
        無(wú)參數(shù)私有化成員方法 testPrivate();
            cls.getDeclaredMethod("testPrivate");
        有參數(shù)私有化成員方法 testPrivate(String);
            cls.getDeclaredMethod("testPrivate", String.class);


操作Method類(lèi)對(duì)象執(zhí)行方法

Object invoke(Object obj, Object... parameters);
    通過(guò)Method類(lèi)對(duì)象調(diào)用,執(zhí)行對(duì)應(yīng)方法。
    Object obj 執(zhí)行當(dāng)前方法的類(lèi)對(duì)象。
    Object... parameters 對(duì)應(yīng)當(dāng)前方法的實(shí)際參數(shù)列表

package com.qfedu.a_reflect;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * 操作Method類(lèi)對(duì)象
 * 
 * @author 期年之前ying@
 *
 */
public class GetMethodObject {
    public static void main(String[] args) 
            throws ClassNotFoundException, SecurityException, NoSuchMethodException, 
            InstantiationException, IllegalAccessException, IllegalArgumentException, 
            InvocationTargetException {
        /*
         * Class Class.forName(String packageNameAndClassName) 
         *          throws ClassNotFoundException;
         */
        Class cls = Class.forName("com.project.a_reflect.Person");
        
        /*
         * 1. 通過(guò)Class類(lèi)對(duì)象調(diào)用,獲取當(dāng)前類(lèi)內(nèi)的所有非私有化成員方法,
         * 包含從父類(lèi)繼承而來(lái)子類(lèi)可以使用的非私有化方法。
         */
        Method[] methods = cls.getMethods();
        for (Method method : methods) {
            System.out.println(method);
        }
        
        System.out.println();

        /*
         * 2. 獲取當(dāng)前類(lèi)自有成員方法,包括私有化方法,但是不包含父類(lèi)繼承給子類(lèi)的方法
         */
        Method[] declaredMethods = cls.getDeclaredMethods();
        for (Method method : declaredMethods) {
            System.out.println(method);
        }
        System.out.println();
        
        /*
         *  3. 根據(jù)指定方法名字和參數(shù)類(lèi)型,獲取非私有化成員方法
         */
        Method game1 = cls.getMethod("game");
        Method game2 = cls.getMethod("game", String.class);
        
        System.out.println(game1);
        System.out.println(game2);
        System.out.println();
        
        /*
         * 4. 根據(jù)指定的方法名稱(chēng)和參數(shù)類(lèi)型,獲取私有化成員方法
         */
        Method testPrivate1 = cls.getDeclaredMethod("testPrivate");
        Method testPrivate2 = cls.getDeclaredMethod("testPrivate", String.class);
        System.out.println(testPrivate1);
        System.out.println(testPrivate2);
        System.out.println();
        
        /*
         * 調(diào)用方法
         */
        Object object = cls.getConstructor().newInstance();
        game1.invoke(object);
        game2.invoke(object, "World Of Tank");
        
        /*
         * 給予暴力反射操作權(quán)限
         */
        testPrivate1.setAccessible(true);
        testPrivate2.setAccessible(true);
        testPrivate1.invoke(object);
        testPrivate2.invoke(object, "西紅柿+黃瓜+雞蛋+羊肉串");
    }
}

操作 Field 成員變量類(lèi)

通過(guò)Class類(lèi)對(duì)象獲取對(duì)應(yīng)類(lèi)的Field成員變量類(lèi)對(duì)象

Field[] getFields();
    獲取類(lèi)內(nèi)所有非私有化成員變量數(shù)組
    
Field[] getDeclaredFields();
    【暴力反射】
    獲取類(lèi)內(nèi)所有成員變量數(shù)組,包括私有化成員變量
Field getField(String fieldName);
    根據(jù)成員變量名字獲取對(duì)應(yīng)的成員變量對(duì)象,要求當(dāng)前成員變量非私有化
    例如: 
        public int test;
        cls.getField("test");

Field getDeclaredField(String fieldName);
    【暴力反射】
    獲取類(lèi)內(nèi)指定名字的成員變量對(duì)象,包括私有化成員變量
    例如:
        private String name;
        private int id;
        cls.getDeclaredField("name");
        cls.getDeclaredField("id");     


操作Field類(lèi)對(duì)象賦值取值成員變量

Field[] getFields();
    獲取類(lèi)內(nèi)所有非私有化成員變量數(shù)組
    
Field[] getDeclaredFields();
    【暴力反射】
    獲取類(lèi)內(nèi)所有成員變量數(shù)組,包括私有化成員變量
Field getField(String fieldName);
    根據(jù)成員變量名字獲取對(duì)應(yīng)的成員變量對(duì)象,要求當(dāng)前成員變量非私有化
    例如: 
        public int test;
        cls.getField("test");

Field getDeclaredField(String fieldName);
    【暴力反射】
    獲取類(lèi)內(nèi)指定名字的成員變量對(duì)象,包括私有化成員變量
    例如:
        private String name;
        private int id;
        cls.getDeclaredField("name");
        cls.getDeclaredField("id");     


package com.qfedu.a_reflect;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;

/**
 * 操作Field類(lèi)對(duì)象
 * 
 * @author 期年之前ying@
 *
 */
public class GetFieldObject {
    public static void main(String[] args) 
            throws ClassNotFoundException, NoSuchFieldException, SecurityException,
            InstantiationException, IllegalAccessException, IllegalArgumentException, 
            InvocationTargetException, NoSuchMethodException {
        /*
         * Class Class.forName(String packageNameAndClassName) 
         *          throws ClassNotFoundException;
         */
        Class cls = Class.forName("com.project.a_reflect.Person");
        
        /*
         * 1. 獲取類(lèi)內(nèi)所有非私有化成員變量數(shù)組
         */
        Field[] fields = cls.getFields();
        for (Field field : fields) {
            System.out.println(field);
        }
        System.out.println();
        
        /*
         * 2. 獲取類(lèi)內(nèi)所有成員變量數(shù)組,包括私有化成員變量
         */
        Field[] declaredFields = cls.getDeclaredFields();
        for (Field field : declaredFields) {
            System.out.println(field);
        }
        System.out.println();
        
        /*
         * 3. 根據(jù)成員變量名字獲取對(duì)應(yīng)的成員變量對(duì)象,要求當(dāng)前成員變量非私有化
         */
        Field test = cls.getField("test");
        System.out.println(test);
        System.out.println();
        
        /*
         * 4. 獲取類(lèi)內(nèi)指定名字的成員變量對(duì)象,包括私有化成員變量
         */
        Field id = cls.getDeclaredField("id");
        Field name = cls.getDeclaredField("name");
        System.out.println(id);
        System.out.println(name);   
        System.out.println();
        
        /*
         * 取值賦值成員變量
         */
        Object obj = cls.getConstructor().newInstance();
        System.out.println(obj);
        test.set(obj, 100);
        System.out.println(obj);
        System.out.println(test.get(obj));
        
        id.setAccessible(true);
        name.setAccessible(true);
        
        id.set(obj, 10);
        name.set(obj, "大哥好威武");
        System.out.println(obj);
        System.out.println(id.get(obj));
        System.out.println(name.get(obj));
        
        System.out.println();
        System.out.println(id.getType());
        System.out.println(name.getType());
    }
}


暴力反射授權(quán)

class AccessibleObject 類(lèi)內(nèi)方法
public static void setAccessible(AccessibleObject[] array, boolean flag);
    通過(guò)類(lèi)名調(diào)用的靜態(tài)工具方式,給予AccessibleObject類(lèi)對(duì)象或者其子類(lèi)對(duì)象數(shù)組,賦值操作權(quán)限。
    子類(lèi)對(duì)象包括: Field Method Constructor
    
public void setAccessible(boolean flag);
    通過(guò)AccessibleObject類(lèi)對(duì)象調(diào)用,單一權(quán)限授權(quán),F(xiàn)ield Method Constructor都可以使用。

案例操作

需要使用
    1. String方法
    2. IO流 推薦字符流操作
    3. 反射
    4. 自行了解 ==> String 轉(zhuǎn)其他類(lèi)型方法 百度 parse系列方法

文件名:
    studentInfo.txt
文件內(nèi)容:
className=com.qfedu.a_reflect.Student
name=李四
age=18
gender=false
javaScore=59
webScore=59
dbScore=59

目標(biāo)
    文件內(nèi)容轉(zhuǎn)Student類(lèi)對(duì)象

package com.qfedu.a_reflect;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;

@SuppressWarnings("all")
public class ReflectDemo {
    public static void main(String[] args) 
            throws IOException, ClassNotFoundException, InstantiationException, 
            IllegalAccessException, IllegalArgumentException, InvocationTargetException,
            NoSuchMethodException, SecurityException, NoSuchFieldException {
        // 1. 創(chuàng)建緩沖字符輸入流 處理 文件
        BufferedReader br = new BufferedReader(new FileReader("./data/studentInfo.txt"));
        
        // 2. 讀取文件數(shù)據(jù)
        String classInfo = br.readLine();
        String className = classInfo.substring(classInfo.indexOf("=") + 1);
        
        // 3. 啟動(dòng)萬(wàn)惡之源 獲取Class對(duì)象,加載指定類(lèi)
        Class cls = Class.forName(className);
        
        // 4. 創(chuàng)建對(duì)應(yīng)類(lèi)對(duì)象
        Object obj = cls.getConstructor().newInstance();
        
        // 5. 讀取文件,利用循環(huán)操作
        String info = null;
        Object value = null;
        
        // 每一次從文件中讀取一行數(shù)據(jù)
        while ((info = br.readLine()) != null) {
            // 按照 = 分割信息 name=李四
            String[] split = info.split("=");
            System.out.println(Arrays.toString(split));
            // 根據(jù)信息獲取對(duì)應(yīng)成員變量對(duì)象
            Field field = cls.getDeclaredField(split[0]);
            field.setAccessible(true);
            
            // 獲取成員變量數(shù)據(jù)類(lèi)型
            Class type = field.getType();
            
            // 當(dāng)前成員變量數(shù)據(jù)為String類(lèi)型
            if (type.equals(String.class)) {
                value = split[1];
                // field.set(obj, split[1]);
            // 成員變量數(shù)據(jù)類(lèi)型為int類(lèi)型
            } else if (type.equals(int.class)) {
                value = Integer.parseInt(split[1]);
            // 成員變量數(shù)據(jù)類(lèi)型為boolean類(lèi)型
            } else if (type.equals(boolean.class)) {
                value = Boolean.parseBoolean(split[1]);
            }
            
            field.set(obj, value);
        }
        
        System.out.println(obj);
        
        // 關(guān)閉資源
        br.close(); 
    }
}

最后

歡迎關(guān)注公眾號(hào):前程有光,領(lǐng)取一線大廠Java面試題總結(jié)+各知識(shí)點(diǎn)學(xué)習(xí)思維導(dǎo)+一份300頁(yè)pdf文檔的Java核心知識(shí)點(diǎn)總結(jié)! 這些資料的內(nèi)容都是面試時(shí)面試官必問(wèn)的知識(shí)點(diǎn),篇章包括了很多知識(shí)點(diǎn),其中包括了有基礎(chǔ)知識(shí)、Java集合、JVM、多線程并發(fā)、spring原理、微服務(wù)、Netty 與RPC 、Kafka、日記、設(shè)計(jì)模式、Java算法、數(shù)據(jù)庫(kù)、Zookeeper、分布式緩存、數(shù)據(jù)結(jié)構(gòu)等等。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容