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#反射
- C# 可以利用反射給只讀屬性賦值嗎?C#反射賦值
- 修改追加屬性的值
- 反射修改 static final 變數反射變數
- Java反射-屬性Java反射
- 獲取物件屬性型別、屬性名稱、屬性值的研究:反射和JEXL解析引擎物件型別反射
- JavaScript修改連結a的href屬性值JavaScript
- 動態修改input元素type屬性值
- C#通過反射獲取物件屬性,列印所有欄位屬性的值C#反射物件
- 如何防止修改readonly修飾的屬性值
- JavaScript如何動態修改img的src屬性值JavaScript
- jQuery動態修改連結的href屬性值jQuery
- 使用java反射技術完成物件所有屬性值的輸出Java反射物件
- jQuery修改和獲取圖片的src屬性值jQuery
- BackgroundImageLayout屬性值
- 動態修改Shape的solid屬性的color值Solid
- html元素,屬性修改HTML
- iOS UITableView 修改屬性iOSUIView
- 修改物件私有屬性物件
- CSS 屬性賦值CSS賦值
- 求助,怎麼修改 response 響應中的 Cookie 的屬性值Cookie
- Oracle手工修改JOB屬性Oracle
- 反射-通過反射寫一個通用的設定某個物件的某個屬性為指定的值反射物件
- HTML 布林屬性值HTML
- ajax readystate 屬性值
- js如何獲取給定屬性的屬性值JS
- node實現檔案屬性批量修改(時間屬性)
- 修改ASM磁碟組的屬性ASM
- vgchange指令:修改卷組屬性GC
- .NET Reflection 反射 類屬性間的拷貝反射
- 元物件、 屬性 和 反射程式設計物件反射程式設計
- 在url中通過屬性名獲取屬性值
- JavaScript 獲取 checked 屬性值JavaScript
- javascript如何獲取屬性值JavaScript
- CSS border屬性預設值CSS
- jquery設定href屬性值jQuery
- jquery改變元素屬性值jQuery