Java-这段代码中final型字段为什么可以改变?

Java-这段代码中final型字段为什么可以改变?

夜无邪 发布于 2017-03-22 字数 240 浏览 952 回复 2
public static void main(String[] args) throws IOException {
PrintStream out = new PrintStream("D:\d.txt");
System.setOut(out);
System.out.println(System.out == out); //这里打印为true,意外吧
}

如果你对这篇文章有疑问,欢迎到本站 社区 发帖提问或使用手Q扫描下方二维码加群参与讨论,获取更多帮助。

扫码加入群聊

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

夜无邪 2017-10-02 2 楼

final关键字的作用是语法层面上的意义,也就是说定义为final的变量不能够被修改是在编译期间检查的。但是你看看setOut(out)方法的定义,它是一个native方法,这个方法超出了编译器的检测范围,所以是可以绕过这个限制的。

浮生未歇 2017-04-14 1 楼

楼上回答的精辟. final这些东西是为了限制 使用java的这些 码农的. 开发java的那帮人想怎么玩就怎么玩.
不过, 我们可以通过Unsafe来自己搞一下:

@Test
public void dfsd() throws Exception{
Object[] array1 = new Object[] {new PrintStream("D:\1.txt")};
long baseOffset = getUnsafe().arrayBaseOffset(Object[].class);
long outAddr=normalize(getUnsafe().getInt(array1, baseOffset));
long o2=getUnsafe().staticFieldOffset(System.class.getField("out"));
getUnsafe().putLong(System.class, o2, outAddr);
System.out.println(System.out == out);
}

private long normalize(int value) {
if (value >= 0) return value;
return (~0L >>> 32) & value;
}

private Unsafe getUnsafe() throws Exception {
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
return (Unsafe) theUnsafe.get(null);
}

打开d:1.txt, 看到 true.

部分代码引自: http://mishadoff.github.io/blog/java-magic-part-4-sun-dot-misc-dot-unsafe/