Java一反射

目錄

一、什么是反射

二、反射的作用和應(yīng)用場(chǎng)景

三、反射的優(yōu)缺點(diǎn)

四、使用反射(獲取Class對(duì)象、獲取類的構(gòu)造方法及其參數(shù)類型和修飾類型、通過構(gòu)造函數(shù)的newInstance方法創(chuàng)建類的實(shí)例、獲取類的方法并調(diào)用它、獲取和修改類的屬性 等等)

五、反射問題探索


一、什么是反射

Java反射機(jī)制是在運(yùn)行狀態(tài)中,對(duì)于任意一個(gè)類,都能夠知道這個(gè)類中的所有屬性和方法;對(duì)于任意一個(gè)對(duì)象,都能夠調(diào)用它的任意一個(gè)方法和屬性;這種動(dòng)態(tài)獲取的信息以及動(dòng)態(tài)調(diào)用對(duì)象的方法的功能稱為java語言的反射機(jī)制。通俗點(diǎn)講,通過反射,該類對(duì)我們來說是完全透明的,想要獲取任何東西都可以。

二、反射的作用和應(yīng)用場(chǎng)景

作用

  • 獲取任意類的名稱、package 信息、所有屬性、方法、注解、類型、類加載器、modifiers、父類、現(xiàn)實(shí)接口等
  • 獲取任意對(duì)象的屬性,并且能改變對(duì)象的屬性
  • 調(diào)用任意對(duì)象的方法
  • 判斷任意一個(gè)對(duì)象所屬的類
  • 實(shí)例化任意一個(gè)類的對(duì)象
  • 生成動(dòng)態(tài)代理。

應(yīng)用場(chǎng)景

1.實(shí)例化系統(tǒng)隱藏的類
2.調(diào)用對(duì)象被隱藏起來的屬性和方法
3.動(dòng)態(tài)代理
4.與注解的結(jié)合使用
5.在編譯時(shí)無法知道該對(duì)象或類可能屬于哪些類,程序在運(yùn)行時(shí)獲取對(duì)象和類的信息

反射的作用和應(yīng)用場(chǎng)景有點(diǎn)類似了,我們只要記住反射的作用,就能在你遇到問題的時(shí)候想起它。反射一般是用來開發(fā)框架,在我們平常的開發(fā)中,反射用得并不多,但是我們必須搞懂它,它可以幫助我們理解一些框架的原理,有一句很經(jīng)典的話就是:反射是框架設(shè)計(jì)的靈魂

三、反射的優(yōu)缺點(diǎn)

優(yōu)點(diǎn)

提高了 Java 程序的靈活性和擴(kuò)展性,降低耦合性,提高自適應(yīng)能力。
允許程序創(chuàng)建和控制任何類的對(duì)象,無需提前硬編碼目標(biāo)類
應(yīng)用很廣,測(cè)試工具、框架都用到了反射

缺點(diǎn)

性能問題:反射是一種解釋操作,遠(yuǎn)慢于直接代碼。因此反射機(jī)制主要用在對(duì)靈活性和擴(kuò)展性要求很高的系統(tǒng)框架上,普通程序不建議使用
模糊程序內(nèi)部邏輯:反射繞過了源代碼,無法再源代碼中看到程序的邏輯,會(huì)帶來維護(hù)問題
增大了復(fù)雜性:反射代碼比同等功能的直接代碼更復(fù)雜

四、使用反射

1、獲取Class類對(duì)象,三種方式

 //通過Class.forName()方法獲取
        try {
            Class test = Class.forName("com.mumumxi.test");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

//通過對(duì)象的getClass()方法獲取
        String string = "test";
        Class test1 = string.getClass();

//直接通過類字面常量獲取
        Class test2 = String.class;
      

2、獲取類的構(gòu)造方法及其參數(shù)類型和修飾語

package com.mumuxi.testapplication;


import java.lang.reflect.Constructor;


/**
 * @author mumuxi
 * @date 2020/1/19
 */
public class Test {

    public static final String TAG = Test.class.getSimpleName();

    public Test() {
    }

    public Test(int i) {
    }

    public Test(int i, String string) {
    }

    public static void main(String[] args) {

        Class test = null;

        try {
            test = Class.forName("com.mumuxi.testapplication.Test");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        //getDeclaredConstructors 返回類的所有構(gòu)造函數(shù),包括私有的
        Constructor[] constructors = test.getDeclaredConstructors();

        for (Constructor constructor : constructors) {
            //通過getParameterTypes 獲取構(gòu)造函數(shù)的參數(shù)Class列表
            for (Class name : constructor.getParameterTypes()) {
                System.out.println(name.getName());
            }

            //通過getModifiers獲取構(gòu)造函數(shù)的修飾類型,是private的還是public..
            System.out.println(constructor.getModifiers());
            System.out.println("--------------------------------");

        }

        //getConstructors 返回public類型的構(gòu)造函數(shù)
        Constructor[] constructors1 = test.getConstructors();


        //獲取無參的構(gòu)造函數(shù)
        try {
            Constructor constructor = test.getDeclaredConstructor();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }

        //獲取只有一個(gè)參數(shù)的構(gòu)造函數(shù),參數(shù)類型是int
        Class[] classes = {int.class};
        try {
            Constructor constructor1 = test.getDeclaredConstructor(classes);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }

        //獲取只有兩個(gè)參數(shù)的構(gòu)造函數(shù),參數(shù)類型依次是int 、String
        Class[] classes1 = {int.class, String.class};
        try {
            Constructor constructor1 = test.getDeclaredConstructor(classes1);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }

    }

}




3、通過構(gòu)造函數(shù)的newInstance方法創(chuàng)建類的實(shí)例

package com.mumuxi.testapplication;


import android.util.Log;

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

/**
 * @author mumuxi
 * @date 2020/1/19
 */
public class Test {

    public static final String TAG = Test.class.getSimpleName();

    public Test() {

    }

    public Test(int i) {

    }

    public Test(int i, String string) {

    }

    public static void main(String[] args) {
        Class test = null;

        try {
            test = Class.forName("com.mumuxi.testapplication.Test");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        Constructor constructor = null;

        //調(diào)用無參構(gòu)造函數(shù)新建類的實(shí)例
        if (test != null) {
            try {
                constructor = test.getDeclaredConstructor();
                constructor.setAccessible(true);
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            }
        }
        if (constructor != null) {
            try {
                Object object = constructor.newInstance();
                if (object instanceof Test) {
                    System.out.println("create object success");
                }
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }

        //調(diào)用含有一個(gè)參數(shù)的構(gòu)造函數(shù)新建類的實(shí)例
        Class[] param = {int.class};
        if (test != null) {
            try {
                constructor = test.getDeclaredConstructor(param);
                constructor.setAccessible(true);
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            }
        }
        if (constructor != null) {
            try {
                Object object = constructor.newInstance(1);
                if (object instanceof Test) {
                    System.out.println("create object success");
                }
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }

        //調(diào)用含有兩個(gè)參數(shù)的構(gòu)造函數(shù)新建類的實(shí)例
        Class[] param1 = {int.class, String.class};
        if (test != null) {
            try {
                constructor = test.getDeclaredConstructor(param1);
                constructor.setAccessible(true);
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            }
        }
        if (constructor != null) {
            try {
                Object object = constructor.newInstance(1, "hehe");
                if (object instanceof Test) {
                    System.out.println("create object success");
                }
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }

    }

}



4、獲取類的方法并調(diào)用它(私有、公共、靜態(tài))

package com.mumuxi.testapplication;


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

/**
 * @author mumuxi
 * @date 2020/1/19
 */
public class Test {
    
    private static final String TAG = Test.class.getSimpleName();
    
    public static void main(String[] args) {

        Test test = new Test();
        Method method = null;

        //獲取一個(gè)對(duì)象的私有或公共方法并調(diào)用它
        try {
            /*通過Class對(duì)象的getDeclaredMethod方法獲取指定方法,
            第一個(gè)參數(shù)是方法名,第二個(gè)參數(shù)是方法的參數(shù)Class對(duì)象列表*/
            method = Test.class.getDeclaredMethod("test", null);
            //method 是私有類型的還需要通過setAccessible給予權(quán)限
            method.setAccessible(true);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        if (method != null) {
            try {
                //通過invoke來執(zhí)行該方法第,一個(gè)參數(shù)是類實(shí)例,第二個(gè)是方法的參數(shù)列表
                method.invoke(test, null);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }


        //獲取指定類的私有方法并調(diào)用它
        try {
            method = Test.class.getDeclaredMethod("test1");
            //method 是私有類型的還需要通過setAccessible給予權(quán)限
            method.setAccessible(true);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        if (method != null) {
            try {
                //通過invoke來執(zhí)行該方法第,一個(gè)參數(shù)是類實(shí)例,第二個(gè)是方法的參數(shù)列表
                method.invoke(null);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }

    }

    private void test() {
        System.out.println("hehe");
    }

    public static void test1(){
        System.out.println("hehe1");
    }
}

5、獲取和修改類的屬性 (私有、公共、靜態(tài))

package com.mumuxi.testapplication;

import java.lang.reflect.Field;


/**
 * @author mumuxi
 * @date 2020/1/19
 */
public class Test {

    public static final String TAG = Test.class.getSimpleName();

    private String test = "test";
    private static String TEST = "TEST";

    public static void main(String[] args) {


        Class test = null;

        try {
            test = Class.forName("com.mumuxi.testapplication.Test");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        //獲取實(shí)例的指定字段并修改它的值
        Object object = null;

        if (test != null) {
            try {
                object = test.newInstance();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            }
        }


        Field field = null;
        if (test != null) {
            try {
                //通過Class對(duì)象的getDeclaredField獲取指定屬性,參數(shù)是屬性名
                field = test.getDeclaredField("test");
                field.setAccessible(true);
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            }
        }


        if (field != null && object != null) {
            try {
                //通過Field的get方法獲取指定實(shí)例的字段,參數(shù)是具體的實(shí)例
                Object fieldObject = field.get(object);
                System.out.println("非靜態(tài)字段------------");
                if (fieldObject instanceof String) {
                    System.out.println("String 類型");
                }
                System.out.println(fieldObject);

                /*通過Field的set方法修改指定實(shí)例的字段
                 第一個(gè)參數(shù)是具體的實(shí)例,第二個(gè)參數(shù)是需要修改的值*/
                field.set(object, "改掉了");
                System.out.println(field.get(object));
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }

        //修改類的靜態(tài)字段
        if (test != null) {
            try {
                //通過Class對(duì)象的getDeclaredField獲取指定屬性,參數(shù)是屬性名
                field = test.getDeclaredField("TEST");
                field.setAccessible(true);
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            }
        }

        try {
            System.out.println("靜態(tài)字段------------");
            Object staticObject = field.get(null);
            System.out.println(staticObject);
            field.set(staticObject, "ABCD");
            System.out.println(field.get(null));
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

    }

}

6、通過Class對(duì)象getSuperclass方法的獲取類的父類

       Class test = null;

        try {
            test = Class.forName("com.mumuxi.testapplication.Test");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        if (test != null) {
            Class superClass = test.getSuperclass();
        }

7、獲取類的接口

Class test = null;

        try {
            test = Class.forName("com.mumuxi.testapplication.Test");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        if (test != null) {
            Class[] interfaces = test.getInterfaces();
        }

推薦使用 Joor反射庫(kù) ,可以參考Java反射庫(kù)jOOR簡(jiǎn)介

五、反射問題探索

1.Java中的final字段真的不能修改么?(怎樣修改final字段)
通過反射是可以修改final字段的!但是一般情況下不建議這么做,如果出現(xiàn)問題也比較難排查。
具體可以參考:https://blog.csdn.net/adu003/article/details/104376399

2.反射可以破壞單例嗎?
反射可以破壞單例,但是我們也可以通過一些方法防御被反射破壞單例。

3.反射的優(yōu)缺點(diǎn)

優(yōu)點(diǎn):

1.能夠運(yùn)行時(shí)動(dòng)態(tài)地獲取類的實(shí)例,提高靈活性

2.與動(dòng)態(tài)編譯結(jié)合

缺點(diǎn):
1)使用反射性能較低,需要解析字節(jié)碼,將內(nèi)存中的對(duì)象進(jìn)行解析。
解決方案:
1、通過setAccessible(true)關(guān)閉JDK的安全檢查來提升反射速度;
2、多次創(chuàng)建一個(gè)類的實(shí)例時(shí),有緩存會(huì)快很多
3、ReflflectASM工具類,通過字節(jié)碼生成的方式加快反射速度
2)相對(duì)不安全,破壞了封裝性(因?yàn)橥ㄟ^反射可以獲得私有方法和屬性)

最后編輯于
?著作權(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)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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