首先給出結論,當定義基本數據類型的變量並且同時賦值的時候,該變量是無法通過反射更改.
此時由於JVM編譯優化機制,任何引用該變量的地方得到都是常量,上簡單代碼:
定義三個final變量,其中兩個為基本數據類型(int和string)
public class TestReflection {
final int primitiveInt = 42;
final Integer wrappedInt = 42;
final String stringValue = "42";
public int getPrimitiveInt() {
return this.primitiveInt;
}
public int getWrappedInt() {
return this.wrappedInt;
}
public String getStringValue() {
return this.stringValue;
}
public void changeField(String name, Object value) throws IllegalAccessException, NoSuchFieldException {
Field field = TestReflection.class.getDeclaredField(name);
field.setAccessible(true);
// 去除final修飾符,final,public等限定符在class文件中以16進制數存儲,詳見《深入理解java虛擬機》-6.3.5
Field modifiers_field = Field.class.getDeclaredField("modifiers");
modifiers_field.setAccessible(true);
modifiers_field.set(field, field.getModifiers() & ~Modifier.FINAL);
field.set(this, value);
System.out.println("reflection: " + name + " = " + field.get(this) );
}
}
下面是測試類
public class AppforReflection {
public static void main(String[] args) {
try {
TestReflection test = new TestReflection();
test.changeField("primitiveInt", 84);
System.out.println("direct: primitiveInt = " + test.getPrimitiveInt());
test.changeField("wrappedInt", 84);
System.out.println("direct: wrappedInt = " + test.getWrappedInt());
test.changeField("stringValue", "84");
System.out.println("direct: stringValue = " + test.getStringValue());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
結果如下:
reflection: primitiveInt = 84
direct: primitiveInt = 42
reflection: wrappedInt = 84
direct: wrappedInt = 84
reflection: stringValue = 84
direct: stringValue = 42
可以看到integer類型的變量被更改為84而int和string類型的變量依然為42
但是有兩種方法可以使其發生改變:
方法1.改變賦值方式,取消編譯時的自動優化,比如string如下賦值,int不變
final String stringValue = (null!=null?"":"42");
結果為:
reflection: primitiveInt = 84
direct: primitiveInt = 42
reflection: wrappedInt = 84
direct: wrappedInt = 84
reflection: stringValue = 84
direct: stringValue = 84//這里改變了
方法2.先定義后賦值:
static final int primitiveInt;
static final Integer wrappedInt;
static String stringValue;
static {//這里改為用靜態代碼塊賦值
primitiveInt = 42;
wrappedInt = 42;
stringValue = "42";
}
結果如下:
reflection: primitiveInt = 84
direct: primitiveInt = 84
reflection: wrappedInt = 84
direct: wrappedInt = 84
reflection: stringValue = 84
direct: stringValue = 84
有了以上的認知,我們可以嘗試改變源碼中的變量,如Integer內部類IntegerCache里的字段(low無法更改,但可以改變high和cache)
private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer cache[]; }
代碼如下:
public class App {
static {
try {
// Class<?> clazz = Class.forName("java.lang.Integer$IntegerCache");
Class<?> clazz = Integer.class.getDeclaredClasses()[0];
// 三個屬性都是25 public static final 1+8+16
Field cache = clazz.getDeclaredField("cache");// [Ljava.lang.Integer;
Field low = clazz.getDeclaredField("low");// int
Field high = clazz.getDeclaredField("high");
// static final
// System.out.println(Modifier.toString(cache.getModifiers()));
cache.setAccessible(true);
low.setAccessible(true);
high.setAccessible(true);
/* 去除final修飾符的影響,將字段設為可修改的 */
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.set(high, high.getModifiers() & ~Modifier.FINAL);
modifiersField.set(low, low.getModifiers() & ~Modifier.FINAL);
modifiersField.set(cache, cache.getModifiers() & ~Modifier.FINAL);
high.set(null, 1000);
low.set(low, -1001);//不起作用
/* 修改cache數組的信息,將數組的大小和內容都修改 */
Integer[] ca = new Integer[3000];
int j = -1001;
for (int k = 0; k < ca.length; k++)
ca[k] = new Integer(j++);
cache.set(null, ca);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Integer a = 160;
System.out.println(a);
}
}
結果你會發現
before modifying :static final
after modifying :static
-713
至於為什么a是-713,可以看一下integer這段源碼:
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
這里我的IntegerCache.high已經更改為了1000,cache一並進行了更改,cache[0]為-1001,
而a的值是160在-128和1000之內所以走if語句
返回的就是cache[160+(-(-128))],即cache[288]
————————————————
版權聲明:本文為CSDN博主「a469357594」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/a469357594/article/details/79166621