日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

java反射设置属性值_Java反射如何有效的修改final属性值详解

發布時間:2024/9/30 java 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java反射设置属性值_Java反射如何有效的修改final属性值详解 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前言

以前寫過一篇 Java 反射修改 final 屬性值,本文將在這里重新溫習一下Java反射如何有效的修改final屬性值,下面話不多說了,來一起看看詳細的介紹:

假設有個類

class Person {

public final String name = "Mike";

}

這里聲明 name 為非靜態的屬性只是為了說明反射修改 final 屬性無關乎靜態不靜態,靜態只是表現在它是一個類屬性,在一個類加載器空間只會有一份拷貝,僅此而已。

創建一個通用方法進行反射修改屬性值

public static void modify(Object object, String fieldName, Object newFieldValue) throws Exception {

Field field = object.getClass().getDeclaredField(fieldName);

Field modifiersField = Field.class.getDeclaredField("modifiers");

modifiersField.setAccessible(true); //Field 的 modifiers 是私有的

modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);

if(!field.isAccessible()) {

field.setAccessible(true);

}

field.set(object, newFieldValue);

}

調用 modify(...)方法試圖修改 person 的 name 屬性

Person person = new Person();

modify(person, "name", "Michael");

System.out.println(person.name); //輸出仍然是 Mike

為什么代碼執行下來沒問題,但輸出又還是原來的值呢?但總是可以通過反射方式獲取到修改后的新值。這就是 Java 編譯器對 final 屬型的內聯優化,即編譯時把該 final 的值直接放到了引用它的地方。即使是反射修改了該屬性,但這種事后處理于事無補。

所以我在標題中所說如何有效的修改 final 屬性值是指:反射修改了 final 屬性值后能夠在后續代碼中使用修改后的值。

如果 Person 有個方法

public String getName() {

return name;

}

在前面代碼反射修改了 name 屬性后,getName()方法也仍然是返回 "Mike"。

那么 Java 會對什么類型的 final 值進行內聯編譯呢?它們基本類型 byte, char, short, int, long, float, double, boolean; 再加上 Literal String 類型(直接雙引號字符串)。只要是不被編譯器內聯優化的 final 屬性都可以通過反射有效的進行修改(修改后能使用到新的值)

String 類型比較特殊, 如果把 Person 類 name 屬性改成用 new String("Mike")

public final String name = new String("Mike");

就能夠有效的使用上面的反射代碼修改 name 的值,最后

modify(person, "name", "Michael");

System.out.println(person.name) //輸出就是 Michael 了

正如基本類型有相應的包裝類型,可以把 new String("Mike")想像為 "Mike" 的包裝類型。也確實是基本類型的 final 包裝類型可以被反射有效的修改,new String("Mike") 也可以。

但我們要是在 IDE 中寫成 new String("Mike") , 可能被告知 new String("")這種格式是冗余的,IDE 又會把它改成 "Mike",重而反射行為變得不正確。

還有,如果 final 屬性值是通過構造函數傳入的能不能有效的被修改,當然可以,因為它也不會被編譯器內聯優化。

總之一句話:只要不會被編譯器內聯優化的 final 屬性就可以通過反射有效的進行修改 -- 修改后代碼中可使用到新的值

為加深印象,我們最后作一個較全面的測試

public class TestFinal {

public static void main(String[] args) throws Exception {

Person jordan = new Person("Chicago");

modify(jordan , "firstName", "Michael");

System.out.println(jordan .firstName); //Mike

modify(jordan , "lastName", "Michael");

System.out.println(jordan.lastName); //Michael

modify(jordan , "age", 51f);

System.out.println(jordan .age); //50.5

modify(jordan , "height", 1.98f);

System.out.println(jordan.height); //1.98

modify(jordan, "address", new Address("ccc", "ddd"));

System.out.println(jordan.address.line1); //ccc

modify(jordan , "city", "Miami");

System.out.println(jordan.city); //Miami

}

}

class Person {

public final String firstName = "Mike";

public final String lastName = new String("Jordan"); //可被有效修改

public final float age = 50.5f;

public final Float height = 1.99f; //可被有效修改

public final Address address = new Address("aaa", "bbb"); //可被有效修改

public final String city; //可被有效修改

public Person(String city) {

this.city = city;

}

}

final class Address {

public final String line1;

public final String line2;

public Address(String line1, String line2) {

this.line1 = line1;

this.line2 = line2;

}

}

我以前也有一人誤區: 就是總以為加了 final 關鍵值,該屬性就會被編譯器內聯優化,就不能用反射有效的進行修改。通過今天的梳理終于清晰的明白了:final 屬性,只要不是基本類型和字面 String,就可以正常使用反射修改它的值。以前曾為了想反射修改某個 final 值還特意把 final 關鍵字給去掉,完全不用這么做。所以對于基本類型和字面 String, final 只是預示著它的值不能被正常的代碼修改。

因此我們在聲明 log 時

private static Logger log = LoggerFactory.getLogger(TestFinal.class);

private static final Logger log = LoggerFactory.getLogger(TestFinal.class);

性能上不會有什么差異,也不會因為多一個 final 而在任何使用到了 log 的地方內聯它。只要留意基本類型和字面 String 就行了。

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作能帶來一定的幫助,如果有疑問大家可以留言交流,謝謝大家對聚米學院的支持。

總結

以上是生活随笔為你收集整理的java反射设置属性值_Java反射如何有效的修改final属性值详解的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。