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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

JAVA反射修改常量,以及其局限

發(fā)布時間:2023/12/3 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 JAVA反射修改常量,以及其局限 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

轉(zhuǎn)載自?JAVA反射修改常量,以及其局限

問題,以及一個解決方案

今天公司的JAVA項目碰到一個問題:在生成xls文件的時候,如果數(shù)據(jù)較多,會出現(xiàn)ArrayIndexOutOfBoundsException。
Google發(fā)現(xiàn)是項中所用的jxl包(開源庫,用以處理xls文件)的一個BUG。
也找到了一個解決辦法:http://www.blogjava.net/reeve/archive/2013/01/11/114564.html——即找到它的源代碼,修改其中的一個靜態(tài)常量,然后重新打包成jar即可。試了一下,這個方法確實可行。


另一個解決方案——反射

不過后來在公司前輩提醒,可以試一下——

利用java的反射,在運行時將需要修改的常量強制更改成我們所需要的值

——這樣就不用修改jxl庫了,只要在我們項目中加幾句就OK了,出問題的概率也會小很多。
于是就研究了一下,雖然最后還是發(fā)現(xiàn)在這個方法在我們的項目不可行,不過還是很有收獲的。

首先,利用反射修改私有靜態(tài)常量的方法

對如下Bean類,其中的INT_VALUE是私有靜態(tài)常量
class Bean{ private static final Integer INT_VALUE = 100; }
修改常量的核心代碼:
System.out.println(Bean.INT_VALUE); //獲取Bean類的INT_VALUE字段 Field field = Bean.class.getField("INT_VALUE"); //將字段的訪問權限設為true:即去除private修飾符的影響 field.setAccessible(true); /*去除final修飾符的影響,將字段設為可修改的*/ Field modifiersField = Field.class.getDeclaredField("modifiers"); modifiersField.setAccessible(true); modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL); //把字段值設為200 field.set(null, 200); System.out.println(Bean.INT_VALUE); 以上代碼輸出的結(jié)果是:

100
200

說明用反射私有靜態(tài)常量成功了。


方案的局限

注意到上述代碼的中的靜態(tài)常量類型是Integer——但是我們項目中實際需要修改的字段類型并不是包裝類型Integer,而是java的基本類型int。

當把常量的類型改成int之后,

class Bean{ private static final int INT_VALUE = 100;//把類型由Integer改成了int }

在其他代碼都不變的情況下,代碼輸出的結(jié)果竟然變成了詭異的:

100
100

而且在調(diào)試的過程中發(fā)現(xiàn),在第二次輸出的時候,內(nèi)存中的Bean.INT_VALUE是已經(jīng)變成了200,但是System.out.println(Bean.INT_VALUE)輸出的結(jié)果卻依然時詭異的100?!

——反射失效了嗎?

又試了其他幾種類型,發(fā)現(xiàn)這種貌似失效的情會發(fā)生在int、long、boolean以及String這些基本類型上,而如果把類型改成Integer、Long、Boolean這種包裝類型,或者其他諸如Date、Object都不會出現(xiàn)失效的情況。

原因

經(jīng)過一系列的研究、推測、搜索等過程,終于發(fā)現(xiàn)了原因:

對于基本類型的靜態(tài)常量,JAVA在編譯的時候就會把代碼中對此常量中引用的地方替換成相應常量值。

參考:Modifying final fields in Java

即對于常量 public static final int maxFormatRecordsIndex = 100 ,代碼

if( index > maxFormatRecordsIndex ){ index = maxFormatRecordsIndex ; }

這段代碼在編譯的時候已經(jīng)被java自動優(yōu)化成這樣的:

if( index > 100){ index = 100; }

所以在INT_VALUE是int類型的時候

System.out.println(Bean.INT_VALUE); //編譯時會被優(yōu)化成下面這樣: System.out.println(100);

所以,自然,無論怎么修改Boolean.INT_VALUE,System.out.println(Bean.INT_VALUE)都還是會依然固執(zhí)地輸出100了。

——這本身是JVM的優(yōu)化代碼提高運行效率的一個行為,但是就會導致我們在用反射改變此常量值時出現(xiàn)類似不生效的錯覺。

這大概是JAVA反射的一個局限吧——修改基本類型的常量時,不是太可靠。


附一下我測試時候的DEMO吧

代碼

import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.Date; public class ForClass { static void setFinalStatic(Field field, Object newValue) throws Exception { field.setAccessible(true); Field modifiersField = Field.class.getDeclaredField("modifiers"); modifiersField.setAccessible(true); modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL); field.set(null, newValue); } public static void main(String args[]) throws Exception { System.out.println(Bean.INT_VALUE); setFinalStatic(Bean.class.getField("INT_VALUE"), 200); System.out.println(Bean.INT_VALUE); System.out.println("------------------"); System.out.println(Bean.STRING_VALUE); setFinalStatic(Bean.class.getField("STRING_VALUE"), "String_2"); System.out.println(Bean.STRING_VALUE); System.out.println("------------------"); System.out.println(Bean.BOOLEAN_VALUE); setFinalStatic(Bean.class.getField("BOOLEAN_VALUE"), true); System.out.println(Bean.BOOLEAN_VALUE); System.out.println("------------------"); System.out.println(Bean.OBJECT_VALUE); setFinalStatic(Bean.class.getField("OBJECT_VALUE"), new Date()); System.out.println(Bean.OBJECT_VALUE); } } class Bean { public static final int INT_VALUE = 100; public static final Boolean BOOLEAN_VALUE = false; public static final String STRING_VALUE = "String_1"; public static final Object OBJECT_VALUE = "234"; } 代碼輸出 100 100 ------------------ String_1 String_1 ------------------ false true ------------------ 234 Fri Apr 25 00:55:05 CST 2014

說明

——其中的Boolean跟Object類型常量被正確修改了,而基本類型int和String的修改則“沒有生效”。

以上代碼輸出的結(jié)果是:

總結(jié)

以上是生活随笔為你收集整理的JAVA反射修改常量,以及其局限的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。