我可以使用反射更改接口常量(JDK9 +)的值吗?

时间:2017-12-15 22:33:28

标签: java reflection

public interface A
{
    int const1 = 5;
}


Class clazz=A.class;

如何使用反射更改const1? clazz.getField(????)

4 个答案:

答案 0 :(得分:1)

  

我可以使用反射更改接口常量(JDK9 +)的值吗?

一般情况下,你不能。当然不在你的例子中。

@ CardinalSystem的答案中提供的反射技巧对于使用编译时常量表达式初始化的任何常量都不起作用

17.5.3. Subsequent Modification of final Fields

  

“即使这样,也会出现许多复杂情况。如果在字段声明中将final字段初始化为常量表达式(第15.28节),则final字段的更改可能会发生变化没有被观察到,因为使用final   在编译时将字段替换为常量表达式的值。“

注意:

  1. 对于当前一代Java工具链/ JVM,“可能无法观察到”实际上是“将不会被观察到”......除非您使用反射来观察字段值。

  2. 这不适用于所有界面字段。虽然接口常量是隐式staticfinal,但它们可以使用不是常量表达式的表达式进行初始化。在这种情况下,反射技巧应该有效...只要您注意处理“内存模型问题”。

  3. Jim Garrison和其他人提出了一个有效的观点,即你不应该做这种事情。它导致维护噩梦 1

    1 - ......榆树街品种。

答案 1 :(得分:0)

您可以首先访问该字段:Field#setAccessible()然后使用  使用getDeclaredField("modifiers")获取访问修饰符,然后您可以使用Field#setInt()更改修饰符,以便修改字段:

public static void main(String args[]) {

    A a = new A() {};       

    try {
        setFinalStatic(a, "const1", 2);
    } catch (Exception e) {
        e.printStackTrace();
    }


}

public static void setFinalStatic(Object parent, String fieldName, Object newValue) throws Exception {
    Field field = parent.getClass().getField(fieldName);
    field.setAccessible(true);

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

    System.out.print("Before : " + field.get(parent));
    field.set(parent, newValue);
    System.out.println("\tAfter : " + field.get(parent));
}

答案 2 :(得分:0)

您不应尝试在运行时更改最终字段。 即使您通过反射更改其值,所有使用此最终字段的类仍将保留原始常量值。

答案 3 :(得分:-1)

只有你必须改变 A =新A(){};

on:

Class c = A.class;

你有界面:)