关于final的思考

关于final的思考

  • final 是声明数据域最终的,不可以修改的,常见的 是类的 序列化ID
  • String 类,其数据域都是 final

修改 final 修饰的属性

反射修改 final 修饰的数据域【非常成功的修改了】

public class Test {
    private final String name = "hello world";
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
        Test test = new Test();
        Field field = test.getClass().getDeclaredField("name");
        field.setAccessible(true);
        field.set(test,"HELLO, WORLD!");
        System.out.println(field.get(test));
        System.out.println(test.name);
    }
}

输出
Hello, WORLD!
hello  world

第一个输出是因为说明运行成功,修改final修饰的对象的属性成功修改;

但是第二个输出,表明了我直接使用 name 的属性却还是输出端额原来的值.

反编译后的代码

public class Test {
   private final String name = "hello world";

   public Test() {
   }

   public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
       Test test = new Test();
       Field field = test.getClass().getDeclaredField("name");
       field.setAccessible(true);
       field.set(test, "HELLO, WORLD!");
       System.out.println(field.get(test));
       PrintStream var10000 = System.out;
       test.getClass();
       var10000.println("hello world");
   }
}

可以看出 使用对象.属性的已经被替换了,这是由于JVM 的内联优化(方法调用(参数压栈,跳转到方法处执行,再调回,处理栈参数,处理返回值))导致的,会直接替换掉使用 final 修饰的字段。【当然也可以关闭内联优化】

修改使用 final 修饰的 static 类属性

public class Test {

    private final static String NAME = "static hello world";

    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
        Test test = new Test();
        
        //修改NAME
        Field sfield = test.getClass().getDeclaredField("NAME");
        sfield.setAccessible(true);
        sfield.set(test,"STATIC HELLO, WORLD!");
        System.out.println(sfield.get(test));
        System.out.println(test.NAME);
    }
}

输出异常  Can not set static final 

修改Field中的modifiers数据域,清除代表final的那个bit,才可以成功修改。

public class Test {

    private final static String NAME = "static hello world";

    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
        Test test = new Test();

        //修改NAME
        Field sfield = test.getClass().getDeclaredField("NAME");
        Field modifiers = sfield.getClass().getDeclaredField("modifiers");
        modifiers.setAccessible(true);
        modifiers.setInt(sfield, sfield.getModifiers() & ~Modifier.FINAL);//fianl标志位置0

        sfield.setAccessible(true);
        sfield.set(test,"STATIC HELLO, WORLD!");
        System.out.println(sfield.get(test));
        System.out.println(test.NAME);

    }
}

输出

STATIC HELLO, WORLD!
static hello world
comments powered by Disqus