簡體   English   中英

在前一次反射之后,設置靜態最終字段的Java反射失敗

[英]Java reflection to set static final field fails after previous reflection

在Java中,事實證明,字段訪問器被緩存,並且使用訪問器具有副作用。 例如:

class A {
    private static final int FOO = 5;
}

Field f = A.class.getDeclaredField("FOO");
f.setAccessible(true);
f.getInt(null); // succeeds

Field mf = Field.class.getDeclaredField("modifiers" );
mf.setAccessible(true);

f = A.class.getDeclaredField("FOO");
f.setAccessible(true);
mf.setInt(f, f.getModifiers() & ~Modifier.FINAL);
f.setInt(null, 6); // fails

class A {
    private static final int FOO = 5;
}

Field mf = Field.class.getDeclaredField("modifiers" );
mf.setAccessible(true);

f = A.class.getDeclaredField("FOO");
f.setAccessible(true);
mf.setInt(f, f.getModifiers() & ~Modifier.FINAL);
f.setInt(null, 6); // succeeds

這是失敗的堆棧跟蹤的相關位:

java.lang.IllegalAccessException: Can not set static final int field A.FOO to (int)6
    at sun.reflect.UnsafeFieldAccessorImpl.throwFinalFieldIllegalAccessException(UnsafeFieldAccessorImpl.java:76)
    at sun.reflect.UnsafeFieldAccessorImpl.throwFinalFieldIllegalAccessException(UnsafeFieldAccessorImpl.java:100)
    at sun.reflect.UnsafeQualifiedStaticIntegerFieldAccessorImpl.setInt(UnsafeQualifiedStaticIntegerFieldAccessorImpl.java:129)
    at java.lang.reflect.Field.setInt(Field.java:949)

這兩個反射訪問當然發生在我的代碼庫的非常不同的部分,我真的不想改變第一個來修復第二個。 有沒有辦法改變第二次反射訪問以確保它在兩種情況下都成功?

我試着看看Field對象,它沒有任何看似他們會幫助的方法。 在調試器中,我注意到在第一個示例中返回的第二個Field上設置了overrideFieldAccessor ,但沒有看到修改器的更改。 不過,我不知道該怎么辦。

如果它openjdk-8 ,我正在使用openjdk-8

如果你想修飾符黑客(不要忘記它是完全黑客 ),你需要在第一次訪問該字段之前更改modifiers私有字段。

所以,在你做f.getInt(null); ,你需要這樣做:

mf.setInt(f, f.getModifiers() & ~Modifier.FINAL);

原因是,無論您有多少不同的實際java.lang.reflect.Field對象,都只為類(*)的每個字段創建一個內部FieldAccessor對象。 而對於檢查final ,當它構建在該FieldAccessor執行修改器進行一次UnsafeFieldAccessorFactory

當確定你無法訪問final static字段時(因為setAccessible覆蓋不起作用,但非靜態的最終字段,但不適用於static最終字段),它將為每次后續反射保持失敗,即使是通過不同的Field對象,因為它一直使用相同的FieldAccessor

(*)禁止同步問題; 作為評論中Field提及的源代碼:

//注意這里沒有使用同步。 為給定的字段生成多個FieldAccessor是正確的(盡管效率不高)。

暫無
暫無

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

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