最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java反射如何有效的修改final屬性值詳解

 更新時間:2017年08月28日 11:01:35   作者:隔葉黃鶯  
最近在工作中遇到一個需求,要利用反射對修飾符為final的成員變量進行修改,所以這篇文章主要給大家介紹了關于Java反射如何有效的修改final屬性值的相關資料,文中通過示例代碼介紹的非常詳細,對需要的朋友可以參考下。

前言

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

假設有個類

class Person {
  public final String name = "Mike";
}

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

創(chuàng)建一個通用方法進行反射修改屬性值

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

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

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

如果 Person 有個方法

public String getName() {
 return name;
}

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

那么 Java 會對什么類型的 final 值進行內聯(lián)編譯呢?它們基本類型 byte, char, short, int, long, float, double, boolean; 再加上 Literal String 類型(直接雙引號字符串)。只要是不被編譯器內聯(lián)優(yōu)化的 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 屬性值是通過構造函數(shù)傳入的能不能有效的被修改,當然可以,因為它也不會被編譯器內聯(lián)優(yōu)化。

總之一句話:只要不會被編譯器內聯(lián)優(yōu)化的 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;
 }
}

我以前也有一人誤區(qū): 就是總以為加了 final 關鍵值,該屬性就會被編譯器內聯(lián)優(yōu)化,就不能用反射有效的進行修改。通過今天的梳理終于清晰的明白了: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 的地方內聯(lián)它。只要留意基本類型和字面 String 就行了。

總結

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

相關文章

  • Java源碼解析阻塞隊列ArrayBlockingQueue介紹

    Java源碼解析阻塞隊列ArrayBlockingQueue介紹

    今天小編就為大家分享一篇關于Java源碼解析阻塞隊列ArrayBlockingQueue介紹,小編覺得內容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-01-01
  • SpringBoot項目在IntelliJ IDEA中如何實現(xiàn)熱部署

    SpringBoot項目在IntelliJ IDEA中如何實現(xiàn)熱部署

    spring-boot-devtools是一個為開發(fā)者服務的一個模塊,其中最重要的功能就是自動應用代碼更改到最新的App上面去。,這篇文章主要介紹了SpringBoot項目在IntelliJ IDEA中如何實現(xiàn)熱部署,感興趣的小伙伴們可以參考一下
    2018-07-07
  • java使用動態(tài)代理來實現(xiàn)AOP(日志記錄)的實例代碼

    java使用動態(tài)代理來實現(xiàn)AOP(日志記錄)的實例代碼

    AOP(面向方面)的思想,就是把項目共同的那部分功能分離開來,比如日志記錄,避免在業(yè)務邏輯里面夾雜著跟業(yè)務邏輯無關的代碼
    2013-09-09
  • Spring Boot拓展XML格式的請求和響應操作過程

    Spring Boot拓展XML格式的請求和響應操作過程

    在我們開發(fā)過程中,我們經(jīng)常使用的參數(shù)絕大多少事HTML和JSON格式的請求和響應處理,但是我們在實際開發(fā)過程中,我們可能經(jīng)歷一些,比如對于XML格式的請求,本文給大家介紹Spring Boot拓展XML格式的請求和響應,感興趣的朋友一起看看吧
    2023-10-10
  • Shiro + JWT + SpringBoot應用示例代碼詳解

    Shiro + JWT + SpringBoot應用示例代碼詳解

    這篇文章主要介紹了Shiro (Shiro + JWT + SpringBoot應用),本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-06-06
  • Java自定義實現(xiàn)鏈隊列詳解

    Java自定義實現(xiàn)鏈隊列詳解

    這篇文章主要為大家詳細介紹了Java自定義實現(xiàn)鏈隊列的相關資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-12-12
  • java 輸入3個數(shù)a,b,c,按大小順序輸出的實例講解

    java 輸入3個數(shù)a,b,c,按大小順序輸出的實例講解

    今天小編就為大家分享一篇java 輸入3個數(shù)a,b,c,按大小順序輸出的實例講解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-07-07
  • Java深入數(shù)據(jù)結構理解掌握抽象類與接口

    Java深入數(shù)據(jù)結構理解掌握抽象類與接口

    在類中沒有包含足夠的信息來描繪一個具體的對象,這樣的類稱為抽象類,接口是Java中最重要的概念之一,它可以被理解為一種特殊的類,不同的是接口的成員沒有執(zhí)行體,是由全局常量和公共的抽象方法所組成,本文給大家介紹Java抽象類和接口,感興趣的朋友一起看看吧
    2022-05-05
  • 詳解pom.xml中maven profile的激活方式

    詳解pom.xml中maven profile的激活方式

    本文主要介紹了詳解pom.xml中maven profile的激活方式,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-01-01
  • Spring實戰(zhàn)之注入嵌套Bean操作示例

    Spring實戰(zhàn)之注入嵌套Bean操作示例

    這篇文章主要介紹了Spring實戰(zhàn)之注入嵌套Bean操作,結合實例形式分析了嵌套Bean相關配置與使用操作技巧,需要的朋友可以參考下
    2019-11-11

最新評論

宝丰县| 洱源县| 铜山县| 宜丰县| 泸定县| 洛扎县| 陇川县| 即墨市| 慈利县| 鄂托克前旗| 华亭县| 靖远县| 普宁市| 西充县| 克东县| 屏东县| 娄底市| 拉孜县| 宝山区| 祁阳县| 巴青县| 集贤县| 杭州市| 平南县| 宁乡县| 华蓥市| 乐都县| 嫩江县| 内黄县| 屯昌县| 兰坪| 凤阳县| 贵定县| 扎囊县| 沙湾县| 四平市| 吉安县| 安远县| 大悟县| 牙克石市| 焉耆|