簡體   English   中英

無法在沒有Exception的情況下修改私有最終靜態變量

[英]Fail to modify private final static variable without Exception

我嘗試修改私有的最終靜態變量,如下所示

    ...try {

        Field f =TargetA.class.getDeclaredField("RECV_TIMEOUT");
        f.setAccessible(true);

        Field modifiersField = Field.class.getDeclaredField("modifiers");
        modifiersField.setAccessible(true);
        modifiersField.setInt(f, f.getModifiers() & ~Modifier.FINAL);

        f.set(null, 12L);

    } catch (Exception e) {
        e.printStackTrace();//not reach here!
    } ...

    class TargetA{
        private static final long RECV_TIMEOUT = 180000L;
     }

但是TargetA.RECV_TIMEOUT仍然是180000L,沒有任何異常。 我在StackOverflow中搜索了問題,但找不到解決方案。

我猜Java版本1.6在反射中有更多的限制,這打破了OO規則。 謝謝你的建議!

您可以通過這種方式更改靜態最終字段,如果使用反射查看值,則會更改。 您遇到的問題是編譯器在編譯時只進行一次內聯常量優化。 這意味着可以更改值,但不會更改使用常量的位置。

解決這個問題的方法是使用包裝器方法來“混淆”編譯器,這樣就不必改變使用常量的方式。

public static final long RECV_TIMEOUT = runtime(180000L);

public static final <T> T runtime(T t) { return t; }

通過反射修改final字段具有許多限制。 特別是,如果final字段由編譯時常量初始化,則可能無法觀察到其新值( JLS 17.5.3最終字段的后續修改 )。

您可以使用以下解決方法:

class TargetA{
     private static final long RECV_TIMEOUT = defaultTimeout();     

     private static long defaultTimeout() { return 180000L; }
} 

嘗試在更改后添加以下代碼,您將看到它已更改。

Field e =TargetA.class.getDeclaredField("RECV_TIMEOUT");
e.setAccessible(true);
System.out.println(e.getLong(modifiersField));

然而,引自彼得

這意味着可以更改值,但不會更改使用常量的位置。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM