繁体   English   中英

删除ctor时,无法通过反射设置私有最终字段

[英]Setting private final field via reflection fails when ctor is removed

假设我有以下课程:

public class SomeClass {

    private final int num;

    public SomeClass(int num) {
        this.num = num;
    }

    public int getNum() {
        return num;
    }

}

当我执行此代码来设置num字段时,一切都很好:

SomeClass obj = new SomeClass(0);

final Field field = SomeClass.class.getDeclaredField("num");
field.setAccessible(true);
Field modField = Field.class.getDeclaredField("modifiers");
modField.setAccessible(true);
modField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
field.set(obj, 1);

System.out.println(obj.getNum()); // Prints 1 instead of the initial value 0.

但是,当我从SomeClass删除构造函数时,这将不再起作用,并且println语句将输出0。

谁能解释这种行为?

让我们看看Field.set方法的Java 文档

如果基础字段是最终字段,则该方法将抛出IllegalAccessException,除非已成功为此字段对象使用setAccessible(true),并且该字段是非静态的。 以这种方式设置最终字段仅在反序列化或重构具有空白最终字段的类的实例时才有意义,然后才使程序的其他部分可以访问它们。 在任何其他上下文中使用它可能会产生不可预测的影响,包括程序其他部分继续使用此字段的原始值的情况。

这意味着在您的示例中,如果删除构造函数,则需要将final字段初始化为某个值,从而使其不为空。 在这种情况下,如果使用反射更改最终字段,则可能会产生不可预料的影响,包括程序其他部分继续使用该字段的原始值的情况。

首先,请注意,即使该字段是public ,您也将获得相同的行为,在这种情况下,您无需将field设置为可访问:

final Field field = SomeClass.class.getDeclaredField("num");
Field modField = Field.class.getDeclaredField("modifiers");
modField.setAccessible(true);
modField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
field.set(obj, 1);
System.out.println(obj.num);

这是Java编译器进行优化的结果:实际字段num设置为1 ,但是getNum忽略了该值,因为编译器认为它是final

即使删除了构造函数( demo ),这一行也会打印1

System.out.println(field.get(obj));

Java的编译器会发现final int num从未分配的初始化之外,并取代return num与返回num的初始值。

注意:您的实验提供了一个极好的理由,说明为什么不应该尝试修改您声明不可修改的字段。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM