欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

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

前言

以前寫過(guò)一篇 Java 反射修改 final 屬性值,本文將在這里重新溫習(xí)一下Java反射如何有效的修改final屬性值,下面話不多說(shuō)了,來(lái)一起看看詳細(xì)的介紹:

假設(shè)有個(gè)類

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

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

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

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);
}

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

Person person = new Person();
modify(person, "name", "Michael");
System.out.println(person.name); //輸出仍然是 Mike

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

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

如果 Person 有個(gè)方法

public String getName() {
 return name;
}

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

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

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

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

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

modify(person, "name", "Michael");
System.out.println(person.name) //輸出就是 Michael 了

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

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

還有,如果 final 屬性值是通過(guò)構(gòu)造函數(shù)傳入的能不能有效的被修改,當(dāng)然可以,因?yàn)樗膊粫?huì)被編譯器內(nèi)聯(lián)優(yōu)化。

總之一句話:只要不會(huì)被編譯器內(nèi)聯(lián)優(yōu)化的 final 屬性就可以通過(guò)反射有效的進(jìn)行修改 --  修改后代碼中可使用到新的值

為加深印象,我們最后作一個(gè)較全面的測(cè)試

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 關(guān)鍵值,該屬性就會(huì)被編譯器內(nèi)聯(lián)優(yōu)化,就不能用反射有效的進(jìn)行修改。通過(guò)今天的梳理終于清晰的明白了:final 屬性,只要不是基本類型和字面 String,就可以正常使用反射修改它的值。以前曾為了想反射修改某個(gè) final 值還特意把  final  關(guān)鍵字給去掉,完全不用這么做。所以對(duì)于基本類型和字面 String, final 只是預(yù)示著它的值不能被正常的代碼修改。

因此我們?cè)诼暶?log 時(shí)

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

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

性能上不會(huì)有什么差異,也不會(huì)因?yàn)槎嘁粋€(gè) final 而在任何使用到了 log 的地方內(nèi)聯(lián)它。只要留意基本類型和字面 String 就行了。

總結(jié)

以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來(lái)一定的幫助,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)腳本之家的支持。

相關(guān)文章

  • Spring事務(wù)執(zhí)行流程及如何創(chuàng)建事務(wù)

    Spring事務(wù)執(zhí)行流程及如何創(chuàng)建事務(wù)

    這篇文章主要介紹了Spring事務(wù)執(zhí)行流程及如何創(chuàng)建事務(wù),幫助大家更好的理解和學(xué)習(xí)使用spring框架,感興趣的朋友可以了解下
    2021-03-03
  • 基于springboot redirect重定向路徑問(wèn)題總結(jié)

    基于springboot redirect重定向路徑問(wèn)題總結(jié)

    這篇文章主要介紹了springboot redirect重定向路徑問(wèn)題總結(jié),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • Java基礎(chǔ)之集合框架詳解

    Java基礎(chǔ)之集合框架詳解

    這篇文章主要介紹了Java基礎(chǔ)之集合框架詳解,文中有非常詳細(xì)的代碼示例,對(duì)正在學(xué)習(xí)java的小伙伴們有非常好的幫助,需要的朋友可以參考下
    2021-04-04
  • 10種簡(jiǎn)單的Java性能優(yōu)化

    10種簡(jiǎn)單的Java性能優(yōu)化

    你是否正打算優(yōu)化hashCode()方法?是否想要繞開正則表達(dá)式?Lukas Eder介紹了很多簡(jiǎn)單方便的性能優(yōu)化小貼士以及擴(kuò)展程序性能的技巧
    2017-11-11
  • spring boot 項(xiàng)目中使用thymeleaf模板的案例分析

    spring boot 項(xiàng)目中使用thymeleaf模板的案例分析

    這篇文章主要介紹了spring boot 項(xiàng)目中使用thymeleaf模板的案例分析,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-09-09
  • 實(shí)例講解Java編程中數(shù)組反射的使用方法

    實(shí)例講解Java編程中數(shù)組反射的使用方法

    這篇文章主要介紹了Java編程中數(shù)組反射的使用方法,通過(guò)編寫數(shù)組反射工具類可以重用許多基礎(chǔ)代碼,減少對(duì)類型的判斷過(guò)程,需要的朋友可以參考下
    2016-04-04
  • 一篇文章教會(huì)你使用java爬取想要的資源

    一篇文章教會(huì)你使用java爬取想要的資源

    這篇文章主要介紹了使用java爬蟲爬取想要的資源,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-08-08
  • java ReentrantLock詳解

    java ReentrantLock詳解

    這篇文章主要介紹了java ReentrantLock,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-04-04
  • Springboot配置圖片虛擬映射示例代碼

    Springboot配置圖片虛擬映射示例代碼

    這篇文章主要給大家介紹了關(guān)于Springboot配置圖片虛擬映射的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用springboot具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2021-11-11
  • Spring中Eureka的服務(wù)下線詳解

    Spring中Eureka的服務(wù)下線詳解

    這篇文章主要介紹了Spring中Eureka的服務(wù)下線詳解,根據(jù)默認(rèn)的策略,如果在一定的時(shí)間內(nèi),客戶端沒有向注冊(cè)中心發(fā)送續(xù)約請(qǐng)求,那么注冊(cè)中心就會(huì)將該實(shí)例從注冊(cè)中心移除,需要的朋友可以參考下
    2023-11-11

最新評(píng)論