一、背景
日常磨刀
二、閱前須知知識點:
- 當final修飾的成員變量在定義的時候初始化值,反射就不能動態修改它的值了。
- 當final修飾的成員變量在定義的時候沒有初始化值,就還能通過反射來動態修改它的值。
- 反射機制中的 setAccessible 代表的權限含義
三、舉例(這裏只用基本數據類型和包裝類來討論)
1、不能被修改的情況,直接貼代碼講
//創建一個實體類
public class Demo {
private final int info = 123;
public int getInfo() {
return info;
}
}
//反射修改的代碼區域
public class TestFianl {
public static void main(String[] args) {
try {
test();
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
public static void test() throws NoSuchFieldException, IllegalAccessException {
Demo demo = new Demo();
System.out.println("反射修改之前 Demo 實例的值:"+demo.getInfo());
Field field = demo.getClass().getDeclaredField("info");
field.setAccessible(true);//靈魂語句
field.set(demo, 789);
System.out.println("反射修改之後 Field 實例的值:"+field.get(demo));
System.out.println("反射修改之後 Demo 實例的值:"+demo.getInfo());
}
}
//輸出結果爲:
反射修改之前 Demo 實例的值:123
反射修改之後 Field 實例的值:789
反射修改之後 Demo 實例的值:123
解釋:
1、注意這裏的 修改的 成員變量 info 是被基本數據類型 int 修飾的
2、編譯的時候 被final修飾的成員變量會被優化,所有用到該變量的地方都被替換成了變量的內容 123
第二句話解釋看以下Demo 類反編譯的代碼
public class Demo
{
private final int info = 123;
public int getInfo() {
return 123;//直接返回了 123 這個內容 而不是 info 這個變量
}
}
2、能被修改的情況
//創建一個實體類
public class Demo {
private final Integer info = 123;
public Integer getInfo() {
return info;
}
}
//反射修改的代碼區域 和 1 中的沒有區別
public class TestFianl {
public static void main(String[] args) {
try {
test();
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
public static void test() throws NoSuchFieldException, IllegalAccessException {
Demo demo = new Demo();
System.out.println("反射修改之前 Demo 實例的值:"+demo.getInfo());
Field field = demo.getClass().getDeclaredField("info");
field.setAccessible(true);//靈魂語句
field.set(demo, 789);
System.out.println("反射修改之後 Field 實例的值:"+field.get(demo));
System.out.println("反射修改之後 Demo 實例的值:"+demo.getInfo());
}
}
//輸出結果爲:
反射修改之前 Demo 實例的值:123
反射修改之後 Field 實例的值:789
反射修改之後 Demo 實例的值:789
解釋:
1、注意這裏的 修改的 成員變量 info 是被 包裝類 Integer 修飾的
2、定義的時候並沒有初始化值,getInfo方法返回的是info這個變量
以下Demo 類反編譯的代碼
public class Demo
{
private final Integer info = Integer.valueOf(123);//定義的時候檢查再初始化了值
public Integer getInfo() {
return this.info;
}
}
四、總結
所以成員變量在定義的時候沒有初始化值的時候,就算用final修飾,一樣可以被通過反射之後進行修改