能否通過反射修改被 final 修飾的成員變數?
阿新 • • 發佈:2018-12-22
一、背景
日常磨刀
二、閱前須知知識點:
- 當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修飾,一樣可以被通過反射之後進行修改