反射:您不了解的小知識

一、反射是否可以修改final類型變量?

先看一段代碼
public class ReflectTest {
    //被final修飾的變量
    public final int number = 1 ;
   public int getNumber() {
        return number;
    }

    public static void main(String[] args) throws Exception {
        ReflectTest reflectTest = new ReflectTest();
        Field numberField = ReflectTest.class.getDeclaredField("number");
        numberField.setAccessible(true);
        //通過反射將number的值由1改為2
        numberField.set(reflectTest, 2);
        System.out.println(reflectTest.number);
    }
}

運(yùn)行結(jié)果:

> Task :reflect:ReflectTest.main()
1

我明明通過反射將number的值由1 變成了 2 ,但是我們打印的結(jié)果還是1。
我們接下來看一下它的class文件

ReflectTest.class.jpg
我們發(fā)現(xiàn):被final修飾的變量,是編譯時常量,JVM在編譯的時候就可以知道它的值,直接將初始化的值寫死在上面了。編譯期間final類型的數(shù)據(jù)自動被優(yōu)化

最終:我們獲取的值還是1。
問題來了:反射難道就真的不能修改final的值嗎?

答案是可以的。

  • 修改代碼1如下:
public class ReflectTest {
    //編譯期間final類型的數(shù)據(jù)自動被優(yōu)化
    public final int number = 1  ;

    public static void main(String[] args) throws Exception {
        ReflectTest reflectTest = new ReflectTest();
        Field numberField  = ReflectTest.class.getDeclaredField("number");
        numberField .setAccessible(true);
        numberField .set(reflectTest, 2);
         // 通過反射方法,動態(tài)的去拿
        System.out.println(numberField .get(reflectTest));
    }
}

打印結(jié)果:

> Task :reflect:ReflectTest.main()
2
  • 修改代碼2如下:
public class ReflectTest {
    //編譯期間final類型的數(shù)據(jù)自動被優(yōu)化
    public final int number ;
  //todo 在構(gòu)造函數(shù)中初始化
    public ReflectTest() {
            number = 1;
    }

    public static void main(String[] args) throws Exception {
        ReflectTest reflectTest = new ReflectTest();
        Field numberField  = ReflectTest.class.getDeclaredField("number");
        numberField .setAccessible(true);
        numberField .set(reflectTest, 2);

        System.out.println(reflectTest.number);
    }
}

打印結(jié)果:

> Task :reflect:ReflectTest.main()
2

二、反射為什么慢?

1.Method#invoke 需要進(jìn)行自動拆裝箱

1、反射的invoke方法的參數(shù)是 Object[] 類型,如果是基本數(shù)據(jù)類型會轉(zhuǎn)化為Integer裝箱,同時再包裝成Object數(shù)組。在執(zhí)行時候又會把數(shù)組拆解開,并拆箱為基本數(shù)據(jù)類型。拆箱和裝箱需要時間。
2、反射的Class.forName屬于native方法,native方法就要經(jīng)過語言執(zhí)行層面轉(zhuǎn)換。也就是java到C層再切換到Java層耗時。

2、需要檢查方法

反射時需要檢查方法可見性以及每個實際參數(shù)與形式參數(shù)的類型匹配性

2、編譯器無法對動態(tài)調(diào)用的代碼做優(yōu)化,比如內(nèi)聯(lián)

反射涉及到動態(tài)解析的類型,影響內(nèi)聯(lián)判斷并且無法進(jìn)行JIT

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

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

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