为什么反射可以修改掉final的值?

fun initTypeface( name:String, path :String) {
    try {
        val field = Typeface::class.java.getDeclaredField(name)
        field.isAccessible = true
        field.set(null, Typeface.createFromAsset(CoreApp.get().assets, path))
    } catch (e: NoSuchFieldException) {
        e.printStackTrace()
    } catch (e: IllegalAccessException) {
        e.printStackTrace()
    }
}

上面代码是我的一个用来修改字体的方法。用到了反射修改Typeface类中的字段。

    /** The NORMAL style of the default serif typeface. */
    public static final Typeface SERIF;
    //...
    
       static {
        init();
        // Set up defaults and typefaces exposed in public API
        //..
        SERIF           = create("serif", 0);
        //..
    }

可以看到这个静态成员在初始化的时候就被赋值了。但是我的反射方法却有效果?的确修改掉了字段。

所以我就写了以下代码来看反射是否能修改字段。

//FinalTest
class FinalTest {
    public static void main(String[] args) {
        try {
            Field field = TestHelper.class.getDeclaredField("ENTITY");
            field.setAccessible(true);
            Entity entity = new Entity("reflection name");
            field.set(null, entity);
        } catch (Exception e) {
            e.printStackTrace();
        }

        System.out.println(TestHelper.getENTITY().name);
    }



    static class Entity {

        public String name;

        public Entity(String name) {
            this.name = name;
        }
    }
}


//..TestHelper
class TestHelper {
    private static final FinalTest.Entity ENTITY;

    static {
        ENTITY = new FinalTest.Entity("init name");
    }

    public static FinalTest.Entity getENTITY() {
        return ENTITY;
    }
}

想通过反射的方法修改TestHelper中的ENTITY字段,但是没有成功 。没有被修改掉。而且抛出了异常。

 Can not set static final com.company.finaltest.Entity field
java.lang.IllegalAccessException: Can not set static final com.company.finaltest.Entity field com.company.finaltest.TestHelper.ENTITY to com.company.finaltest.Entity
    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 com.company.finaltest.FinalTest.main(FinalTest.java:13)

所以我就很奇怪,为什么一开始的代码可以修改掉final的值?

——————————
更新,是因为我的代码被编译器优化了?

阅读 3.6k
1 个回答

kotlin不知道,但Java确实不允许修改静态常量字段的值,非静态的可以。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题