深入理解Java反射

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語(yǔ)言的反射機(jī)制。

反射的本質(zhì)就是:在運(yùn)行時(shí),把 Java 類中的各種成分映射成一個(gè)個(gè)的 Java 對(duì)象。

反射機(jī)制很重要的一點(diǎn)就是“運(yùn)行時(shí)”,其使得我們可以在程序運(yùn)行時(shí)加載、探索以及使用編譯期間完全未知的 .class 文件。換句話說(shuō),Java 程序可以加載一個(gè)運(yùn)行時(shí)才得知名稱的 .class 文件,然后獲悉其完整構(gòu)造,并生成其對(duì)象實(shí)體、或?qū)ζ?fields(變量)設(shè)值、或調(diào)用其 methods(方法)。

Class類將一個(gè)類的組成封裝成各個(gè)屬性,并實(shí)現(xiàn)了各個(gè)getXxx()方法。

    public static void getInfo(Class cls) throws NoSuchMethodException {
        //構(gòu)造方法
        cls.getConstructor();

        //獲取某個(gè)方法
        cls.getMethod("");

        //包含的方法
        cls.getMethods();

        //獲取某個(gè)屬性
        cls.getField("");

        //包含的屬性
        cls.getFields();

        //實(shí)現(xiàn)的接口
        cls.getInterfaces();

        //包含的Annotation
        cls.getAnnotations();

        //內(nèi)部類
        cls.getDeclaredClasses();

        //外部類
        cls.getDeclaringClass();

        //獲取類名
        cls.getName();

        //獲取包名
        cls.getPackage();

        //獲取修飾符
        cls.getModifiers();
    }
創(chuàng)建使用類
public class FatherClass {

    protected String mFatherName;
    protected int mFatherAge;

    public FatherClass() {
    }
}

public class SonClass extends FatherClass {

    private String mSonName;
    protected int mSonAge;
    public String mSonBirthday;

    @GET("https:\\www.baidu.com")
    private <T,K> String toStr(T t, K k) {
        return t.toString() + k.toString();
    }

    public String getmSonName() {
        return mSonName;
    }

    public void setmSonName(String mSonName) {
        this.mSonName = mSonName;
    }

}

各種操作實(shí)現(xiàn):

  • 通過(guò)反射獲取類的三種方式
    /**
     * 通過(guò)反射獲取類的三種方式
     * @throws ClassNotFoundException
     */
    private void getClassWay() throws ClassNotFoundException {
        Class cls = null;
        cls = FatherClass.class;
        cls = new FatherClass().getClass();
        cls = Class.forName("com.example.genericannotaionreflect.reflactdemo.FatherClass");
    }
  • 反射創(chuàng)建實(shí)例
    public static void getConstructor() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException {

        Class<?> cls = StringBuilder.class;
        StringBuilder sb = (StringBuilder) cls.newInstance();
        sb.append("hello");
        System.out.println(sb.toString());

        Class<?> cls2 = String.class;
        //獲取String類帶一個(gè)String參數(shù)的構(gòu)造器
        Constructor constructor = cls2.getConstructor(String.class);
        //根據(jù)構(gòu)造器constructor創(chuàng)建實(shí)例
        String str = (String) constructor.newInstance("hello");
        System.out.println(str);
    }
獲取類的所有變量信息
    /**
     * 通過(guò)反射獲取類的所有變量
     */
    public static void printFileds(Class cls) {
        System.out.println("類名:" + cls.getName());

        // 獲取所有 public 訪問(wèn)權(quán)限的變量
        // 包括本類聲明的和從父類繼承的
        Field[] fields = cls.getFields();

        // 獲取所有本類聲明的變量,包含各種訪問(wèn)權(quán)限
        Field[] declaredFields = cls.getDeclaredFields();

        for (Field field: declaredFields) {
            //獲取訪問(wèn)權(quán)限并輸出
            field.setAccessible(true);
            int modifier = field.getModifiers();
            System.out.println("屬性訪問(wèn)權(quán)限是否是 PROTECTED: " + Modifier.isProtected(modifier));
            //輸出變量的類型及變量名
            System.out.println("屬性類型:" + field.getType().getName() + "屬性名:" + field.getName());
        }
    }
    
     //調(diào)用
     ClassReflact.printFileds(FatherClass::class.java)

打?。?/p>

類名:com.example.genericannotaionreflect.reflactdemo.FatherClass
屬性訪問(wèn)權(quán)限是否是 PROTECTED: true
屬性類型:int屬性名:mFatherAge
屬性訪問(wèn)權(quán)限是否是 PROTECTED: true
屬性類型:java.lang.String屬性名:mFatherName

getFields() :獲取所有 public 訪問(wèn)權(quán)限的變量,非public的獲取不到
getDeclaredFields():獲取所有本類聲明的變量,包含各種訪問(wèn)權(quán)限

  • 獲取類的所有方法的所有元素
    @RequiresApi(api = Build.VERSION_CODES.P)
    public static void printMethods(Class cls) {
        System.out.println("類名:" + cls.getName());

        // 獲取所有 public 訪問(wèn)權(quán)限的方法
        // 包括本類聲明的和從父類繼承的
        Method[] methods = cls.getMethods();

        // 獲取所有本類聲明的方法,包含各種訪問(wèn)權(quán)限
        Method[] declaredMethods = cls.getDeclaredMethods();

        for (Method method : declaredMethods) {
            method.setAccessible(true);

            System.out.println("方法名: " + method.getName());

            System.out.println("屬性訪問(wèn)權(quán)限是否是 public: " + Modifier.isProtected(method.getModifiers()));

            //獲取方法返回值類型
            Class<?> returnType = method.getReturnType();
            System.out.println( "返回類型: " + returnType.getName());

            //獲取方法所有參數(shù)
            Parameter[] parameters = method.getParameters();
            for (Parameter parameter: parameters) {
                System.out.println("擁有參數(shù):" + parameter.getName() + "--" + parameter.getType().getName());
            }

            //獲取方法拋出的異常
            Class<?>[] exceptionTypes = method.getExceptionTypes();

            //獲取方法注解
            Annotation[] annotations = method.getAnnotations();

            //方法是否有某個(gè)注解
            if (method.isAnnotationPresent(GET.class)) {
                GET annotation = method.getAnnotation(GET.class);
                System.out.println(annotation.value());
            }

            //獲取方法參數(shù)類型的泛型參數(shù)
            Type[] genericParameterTypes = method.getGenericParameterTypes();
            for (Type type: genericParameterTypes) {
                System.out.println(type.getTypeName());
            }

        }
    }

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface GET {
    String value();
}

//調(diào)用
ClassReflact.printMethods(SonClass::class.java)

打?。?/p>

類名:com.example.genericannotaionreflect.reflactdemo.SonClass
方法名: toStr
屬性訪問(wèn)權(quán)限是否是 public: false
返回類型: java.lang.String
擁有參數(shù):arg0--java.lang.Object
擁有參數(shù):arg1--java.lang.Object
https:\www.baidu.com
T
K
類名:com.example.genericannotaionreflect.reflactdemo.SonClass
方法名: toStr
屬性訪問(wèn)權(quán)限是否是 public: false
返回類型: java.lang.String
擁有參數(shù):arg0--java.lang.Object
擁有參數(shù):arg1--java.lang.Object
https:\www.baidu.com
T
K
方法名: getmSonName
屬性訪問(wèn)權(quán)限是否是 public: false
返回類型: java.lang.String
方法名: setmSonName
屬性訪問(wèn)權(quán)限是否是 public: false
返回類型: void
擁有參數(shù):arg0--java.lang.String
java.lang.String
  • 反射執(zhí)行某個(gè)對(duì)象的私有方法
    public static void invokeMethod() throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
        Class cls = SonClass.class;
        SonClass sonClass = (SonClass) cls.newInstance();
        Method method = cls.getDeclaredMethod("setmSonName", String.class); //獲取setmSonName方法
        method.setAccessible(true); //可以訪問(wèn)對(duì)象的私有方法
        method.invoke(sonClass, "lala"); //使用 invoke 反射調(diào)用私有方法,傳需要操作的對(duì)象和方法的各個(gè)參數(shù)
        System.out.println(sonClass.getmSonName());
    }
  • 反射操作對(duì)象屬性值
    public static void modifyField() throws NoSuchFieldException, IllegalAccessException {
        Class cls = SonClass.class;

        Field field = cls.getDeclaredField("mSonAge");
        field.setAccessible(true);
        SonClass sonClass = new SonClass();
        field.set(sonClass, 18);
        System.out.println("age: " + sonClass.mSonAge);
    }
java 反射為什么會(huì)耗性能

1.反射調(diào)用過(guò)程中會(huì)產(chǎn)生大量的臨時(shí)對(duì)象,這些對(duì)象會(huì)占用內(nèi)存,可能會(huì)導(dǎo)致頻繁 gc,從而影響性能。
2.反射調(diào)用方法時(shí)會(huì)從方法數(shù)組中遍歷查找,并且會(huì)檢查可見性等操作會(huì)耗時(shí)。
3.反射在達(dá)到一定次數(shù)時(shí),會(huì)動(dòng)態(tài)編寫字節(jié)碼并加載到內(nèi)存中,這個(gè)字節(jié)碼沒(méi)有經(jīng)過(guò)編譯器優(yōu)化,也不能享受JIT優(yōu)化。
4.反射一般會(huì)涉及自動(dòng)裝箱/拆箱和類型轉(zhuǎn)換,都會(huì)帶來(lái)一定的資源開銷。
參考:
https://juejin.cn/post/6844904098207105038

參考:https://juejin.cn/post/6844904005294882830

Github demo地址:

https://github.com/running-libo/GenericAnnotationReflect

最后編輯于
?著作權(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)容

  • 首發(fā)于公眾號(hào):專業(yè)電影評(píng)論 專業(yè)影評(píng) @TOC java反射機(jī)制的應(yīng)用器 開發(fā)的時(shí)候有時(shí)候會(huì)碰到這樣的情況,...
    專業(yè)電影評(píng)論閱讀 387評(píng)論 0 1
  • 深入理解Class對(duì)象 RRTI的概念以及Class對(duì)象作用 認(rèn)識(shí)Class對(duì)象之前,先來(lái)了解一個(gè)概念,RTTI(...
    架構(gòu)師springboot閱讀 1,656評(píng)論 0 3
  • 郭相麟 走在人生路上 如何顯示自己的價(jià)值 需要行走 在不同尋常的路上 這條路 充滿了跌跌撞撞 在秋風(fēng)中 聽不到喃喃...
    郭相麟閱讀 311評(píng)論 0 0
  • 我想把曾經(jīng)的一切屏蔽了,是否看不見也就不想念。 這是我來(lái)到北京的多少天,我不想去算,其實(shí)很短,但我卻覺(jué)得度過(guò)了...
    聽海流淚閱讀 289評(píng)論 0 0
  • 他在成堆的尸骨中執(zhí)長(zhǎng)槍而立,眼前是戰(zhàn)場(chǎng),是所剩無(wú)幾的將士拼死奮戰(zhàn)的身影,卻恍然間想起那個(gè)人臨江而立,一襲白衣...
    瑟阿瑟阿瑟閱讀 325評(píng)論 0 1

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