final屬性值能被反射修改嗎?
在剛哥的知識星球中,看到有網友詢問
反射給final修飾的欄位設值,為啥設值會失敗
,之前也深入學習一下反射,對這個問題有點迷惑,於是學習起來並寫demo實踐一下。
先建立一個Test類,裡面含有final修飾的變數
public class Test {
private final String NAME = "亦袁非猿";
public String getName() {
return NAME;
}
}
然後通過反射修改
public class Client {
public static void main(String[] args) {
Test test = new Test();
Class mClass = test.getClass();
// 獲取NAME變數進行修改
Field field = mClass.getDeclaredField("NAME");
if (field != null) {
field.setAccessible(true);
System.out.println("modify before "+field.get(test));
// 進行修改
field.set(test, "鋼絲");
System.out.println("modify after "+field.get(test));
System.out.println("getName = "+test.getName());
}
}
}
// 輸出:
modify before 亦袁非猿
modify after 鋼絲
getName = 亦袁非猿
看上面的輸出,修改後再反射獲取修改的變數,是修改成功的,但是,呼叫方法獲取,發現返回還是修改前的值,為啥呢?
這裡要涉及到Java虛擬機器,在Java類載入階段的準備階段,會對被final修飾的屬性做優化。在編譯期被優化後的Test.class如下:
public class Test {
private final String NAME = "亦袁非猿";
public String getName() {
// 可以發現,在class中,NAME被直接優化變成"亦袁非猿"了
return "亦袁非猿";
}
}
所以,通過反射修改NAME的值,再呼叫該方法也修改無效。要注意一點,NAME是可以被反射修改且修改成功了。
上面說到,只有基本資料型別和String型別才會做優化導致修改無效。對於包裝類或者物件型別,還是可以修改成功的,不信,看下面的程式碼
private final String JOB = new String("安卓程式設計師");
// 進行反射修改
Field jobField = mClass.getDeclaredField("JOB");
if (jobField != null) {
jobField.setAccessible(true);
System.out.println("modify before "+jobField.get(test));
jobField.set(test, new String("大前端程式設計師"));
System.out.println("modify after "+jobField.get(test));
System.out.println("getJob = "+test.getJOB());
}
// 輸出:
modify before 安卓程式設計師
modify after 大前端程式設計師
getJob = 大前端程式設計師
看到輸出可以發現,final被賦值後,還是可以通過反射重新賦值的。包裝類也是,如下程式碼
private final Integer AGE = new Integer(18);
// 進行反射修改
Field ageFiled = mClass.getDeclaredField("AGE");
if (ageFiled != null) {
ageFiled.setAccessible(true);
System.out.println("modify before "+ageFiled.get(test));
ageFiled.set(test, new Integer(19));
System.out.println("modify after "+ageFiled.get(test));
System.out.println("getAge = "+test.getAge());
}
// 輸出:
modify before 18
modify after 19
getAge = 19
繼續看Test.class檔案,看看被編譯後的內容,沒有被優化替換掉
public class Test {
private final String JOB = new String("安卓程式設計師");
private final Integer AGE = new Integer(18);
public Integer getAge() {
return this.AGE;
}
public String getJOB() {
return this.JOB;
}
}
另外,final型別定義後,不一定需要立馬賦值,可以在構件函式進行初始化,那麼,能否修改呢?said is null,直接上程式碼。
public class Test {
private final String LOCATION;
public Test() {
LOCATION = "廣州";
}
public String getLocation() {
return LOCATION;
}
}
// 通過反射修改
Field locationField = mClass.getDeclaredField("LOCATION");
if (field != null) {
locationField.setAccessible(true);
System.out.println("modify before "+locationField.get(test));
locationField.set(test, "深圳");
System.out.println("modify after "+locationField.get(test));
System.out.println("getName = "+test.getLocation());
}
// 輸出:
modify before 廣州
modify after 深圳
getName = 深圳
同樣還是修改有效的,繼續看Test.class檔案,發現被優化後,建構函式的值,被直接移動到final的定義中,方法返回的是LOCATION的引用。
public class Test {
private final String LOCATION = "廣州";
public Test() {
}
public String getLocation() {
return this.LOCATION;
}
}
總結
回到一開始的問題,final屬性值能否被修改呢?這個就要看final修飾變數的型別以及初始化的時機,通過看編譯後的class檔案就可以知道了。
相關文章
- Java 反射修改類的常量值、靜態變數值、屬性值Java反射變數
- C#反射設定屬性值和獲取屬性值C#反射
- 反射修改 static final 變數反射變數
- 修改追加屬性的值
- Java反射-屬性Java反射
- 如何防止修改readonly修飾的屬性值
- jQuery動態修改連結的href屬性值jQuery
- 動態修改Shape的solid屬性的color值Solid
- html元素,屬性修改HTML
- iOS UITableView 修改屬性iOSUIView
- Java反射動態修改註解的值Java反射
- 根據屬性字串獲取屬性值字串
- 求助,怎麼修改 response 響應中的 Cookie 的屬性值Cookie
- 網站能修改模板嗎?網站
- node實現檔案屬性批量修改(時間屬性)
- HTML 布林屬性值HTML
- 揭秘Java反射:如何輕鬆獲取類的屬性及父類屬性Java反射
- mybatis Selective動態判斷屬性值新增或修改操作,batch批次操作MyBatis
- 強制修改CSS的屬性styleCSS
- [20211206]修改job屬性問題.txt
- JavaScript 獲取 checked 屬性值JavaScript
- checkbox name屬性值注意點
- 【CSS系列】被忽略的content屬性CSS
- 修改Ehcache快取中取到的值,快取中的值也被修改了快取
- HTML 屬性你都懂了嗎HTML
- html中Position屬性值介紹和position屬性四種用法HTML
- iOS使用shell指令碼批量修改屬性iOS指令碼
- DB2 修改表列相關屬性DB2
- C# 獲取修改了哪些屬性C#
- HTML id屬性值不能重複HTML
- C# 類相同屬性賦值C#賦值
- Visual Studio 檔案 BuildAction 屬性值UILDA
- 數值常用的屬性和方法
- <a>為空使用href屬性值填充
- 物件屬性值賦給變數物件變數
- Python __dict__屬性:檢視物件內部所有屬性名和屬性值組成的字典Python物件
- JavaScript物件屬性是有序的嗎?JavaScript物件
- java判斷實體內中屬性值內容是否有變更(包含父類屬性值)Java