java 常量反射_Java 反射常量

问:下面程序段中几个 invokeX 方法在运行时哪些可以达到预期效果?哪些不能?为什么?

public class Test {

private static final Integer KEY_EXIT = 1024;

private static void invok1() throws NoSuchFieldException, IllegalAccessException {

System.out.println("invok1->"+Test.KEY_EXIT);

Field field = Test.class.getDeclaredField("KEY_EXIT");

field.setAccessible(true);

field.set(null, 1000);

System.out.println("invok1-

}

private static void invok2() throws NoSuchFieldException, IllegalAccessException {

System.out.println("invok2->"+Test.KEY_EXIT);

Field field = Test.class.getField("KEY_EXIT");

field.set(null, 512);

System.out.println("invok2-

}

private static void invok3() throws NoSuchFieldException, IllegalAccessException {

System.out.println("invok3->"+Test.KEY_EXIT);

Field field = Test.class.getDeclaredField("KEY_EXIT");

field.setAccessible(true);

Field modifiersField = Field.class.getDeclaredField("modifiers");

modifiersField.setAccessible(true);

modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);

field.set(null, 256);

System.out.println("invok3-

}

public static void main(String[] args) throws Exception {

invok1();

invok2();

invok3();

}

}

答:上面程序运行结果如下。

//invok1运行结果

invok1->1024

Exception in thread "main" java.lang.IllegalAccessException: Can not set static final java.lang.Integer field Test.KEY_EXIT to java.lang.Integer

at sun.reflect.UnsafeFieldAccessorImpl.throwFinalFieldIllegalAccessException(UnsafeFieldAccessorImpl.java:76)

at sun.reflect.UnsafeFieldAccessorImpl.throwFinalFieldIllegalAccessException(UnsafeFieldAccessorImpl.java:80)

at sun.reflect.UnsafeQualifiedStaticObjectFieldAccessorImpl.set(UnsafeQualifiedStaticObjectFieldAccessorImpl.java:77)

at java.lang.reflect.Field.set(Field.java:764)

at Test.invok1(Test.java:14)

at Test.main(Test.java:37)

//invok2运行结果

invok2->1024

Exception in thread "main" java.lang.NoSuchFieldException: KEY_EXIT

at java.lang.Class.getField(Class.java:1703)

at Test.invok2(Test.java:20)

at Test.main(Test.java:38)

//invok3运行结果

invok3->1024

invok3-<256

对于 invok1 方法来说成功获取了 KEY_EXIT 静态常量,但是由于是 final 常量的,不允许直接修改,所以直接调用 set 时发生修改异常。

对于 invok2 方法来说 getFields() 方法只能获得某个类及其父类中的所有的 public 字段,而 getDeclaredFields() 方法却能获得某个类(不包括父类)的所有字段(包括 public、private、proteced 等。同样类似的还有 getConstructors() 和 getDeclaredConstructors()、getMethods() 和 getDeclaredMethods() 方法,所以 invok2 会提示找不到字段而崩溃。

对于 invok3 来说就是标准的反射修改静态常量操作。

问:下面程序段中几个 invokeX 方法的运行结果是什么?

public class Test {

private static final int KEY_EXIT = 1024;

private static int KEY_BACK = 1025;

private static final String KEY_STR = "1001";

private static void invok1() throws NoSuchFieldException, IllegalAccessException {

System.out.println("invok1->"+Test.KEY_EXIT);

Field field = Test.class.getDeclaredField("KEY_EXIT");

field.setAccessible(true);

Field modifiersField = Field.class.getDeclaredField("modifiers");

modifiersField.setAccessible(true);

modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);

field.set(null, 256);

System.out.println("invok1-

}

private static void invok2() throws NoSuchFieldException, IllegalAccessException {

System.out.println("invok2->"+Test.KEY_BACK);

Field field = Test.class.getDeclaredField("KEY_BACK");

field.setAccessible(true);

field.set(null, 1000);

System.out.println("invok2-

}

private static void invok3() throws NoSuchFieldException, IllegalAccessException {

System.out.println("invok3->"+Test.KEY_STR);

Field field = Test.class.getDeclaredField("KEY_STR");

field.setAccessible(true);

Field modifiersField = Field.class.getDeclaredField("modifiers");

modifiersField.setAccessible(true);

modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);

field.set(null, "512");

System.out.println("invok3-

}

public static void main(String[] args) throws Exception {

invok1();

invok2();

invok3();

}

}

答:上面程序运行结果如下。

//invok1运行结果

invok1->1024

invok1-<1024

//invok2运行结果

invok2->1025

invok2-<1000

//invok3运行结果

invok3->1001

invok3-<1001

有趣的事情发生了。你可能会去 debug 断点调试 invok1 和 invok3,你会发现相关成员属性都得到了正确的反射修改值,但是为什么输出却不是反射修改后的值?

其实原因很简单,当我们定义基本类型的 final 常量或者 String 类型的 final 常量时(只要为 final,不限制有无 static),如果在编译时能确定其确切值则编译器会将其用到的地方用其实际值进行替换,譬如

static final int A = 23;

println(A);

if(i > A) {}

这样的语句会被编译成

static final int A = 23;

println(23);

if(i > 23) {}

的形式,所以即便运行时反射成功也没有任何意义,因为相关值已经在编译时被替换为了常量,而对于包装类型则没事。

所以在反射 final 修饰的变量时一定要留意其是否会在编译时被替换的问题,否则不但不会报错还会给自己带来不必要的错觉麻烦。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值