为什么在更改字段修饰符之前我不能使用方法get(java.lang.reflect.Field#get) [英] why I can`t use method get(java.lang.reflect.Field#get) before changing field`s modifiers

查看:720
本文介绍了为什么在更改字段修饰符之前我不能使用方法get(java.lang.reflect.Field#get)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

java代码如下。

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

public class Test {
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
        C c = new C();
        Field field = c.getClass().getDeclaredField("NAME");
        field.setAccessible(true);
        System.out.println(field.get(c));//Cause program exception on line 15 while using method get(java.lang.reflect.Field#get).

        Field modifiers = field.getClass().getDeclaredField("modifiers");
        modifiers.setAccessible(true);
        modifiers.setInt(field, field.getModifiers() & ~Modifier.FINAL);
        System.out.println(Modifier.toString(field.getModifiers()));
        field.set(c,"James");
        System.out.println(field.get(c));
    }

}

class C{
    private static final String NAME = "Clive";

    public String toString(){
        return NAME;
    }
}

使用java时发生异常。 lang.reflect.Field #set.Exception信息如下。但是,如果我在第9行删除代码(System.out.println(field.get(c));),则不会发生异常

Exception in thread "main" java.lang.IllegalAccessException: Can not set static final java.lang.String field C.NAME to java.lang.String
    at sun.reflect.UnsafeFieldAccessorImpl.throwFinalFieldIllegalAccessException(UnsafeFieldAccessorImpl.java:73)
    at sun.reflect.UnsafeFieldAccessorImpl.throwFinalFieldIllegalAccessException(UnsafeFieldAccessorImpl.java:77)
    at sun.reflect.UnsafeQualifiedStaticObjectFieldAccessorImpl.set(UnsafeQualifiedStaticObjectFieldAccessorImpl.java:77)
    at java.lang.reflect.Field.set(Field.java:741)
    at Test.main(Test.java:15)


推荐答案

字段懒惰地创建一个名为的对象FieldAccessor 实际上负责获取设置操作。这可以在 Field.get 存档)。您可以单击方法 getFieldAccessor 以深入调用堆栈。这将(目前)最终将您带到一个方法 sun.reflect.UnsafeFieldAccessorFactory.newFieldAccessor archive )你可以看到修饰符被读取一次然后被烘焙到字段访问器的实际类型。

Field lazily creates an object called a FieldAccessor which is actually responsible for get and set operations. This can be seen in the source code for Field.get (archive). You can click on the method getFieldAccessor to go deeper in to the call stack. This will (at the moment) eventually take you to a method sun.reflect.UnsafeFieldAccessorFactory.newFieldAccessor (archive) where you can see that the modifiers are read once and then baked in to the actual type of the field accessor.

在更改修饰符之前调用 Field.get 会影响输出,因为它导致在 final 被删除之前实例化字段访问器。

Calling Field.get before changing the modifiers affects the output because it causes the field accessor to be instantiated before final is removed.

你是可能会使用类似下面的代码来清除字段访问器:

You could possibly use something like the following bit of code to clear the field accessors:

public static void clearFieldAccessors(Field field)
        throws ReflectiveOperationException {
    Field fa = Field.class.getDeclaredField("fieldAccessor");
    fa.setAccessible(true);
    fa.set(field, null);

    Field ofa = Field.class.getDeclaredField("overrideFieldAccessor");
    ofa.setAccessible(true);
    ofa.set(field, null);

    Field rf = Field.class.getDeclaredField("root");
    rf.setAccessible(true);
    Field root = (Field) rf.get(field);
    if (root != null) {
        clearFieldAccessors(root);
    }
}

使用它会导致问题中的代码通过,如果在 field.get(...)之间插入 clearFieldAccessors(field) field.set(...)

Using that causes the code in the question to pass, if you insert clearFieldAccessors(field) in between field.get(...) and field.set(...).

当然,无法保证任何一项必须有效,并且可能 clearFieldAccessors 中的代码会导致一些我不知道的问题。

There is, of course, no guarantee that any of this has to work, and it's possible that the code in clearFieldAccessors will cause some problem that I'm unaware of.

这篇关于为什么在更改字段修饰符之前我不能使用方法get(java.lang.reflect.Field#get)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆