关于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