虽然我已经多次这样做而没有引起注意,但我刚刚发生这种情况:System.setIn()
正在重新分配静态最终System.in
。
我错过了什么吗?如何重新分配最终字段。
答案 0 :(得分:7)
通常,不能修改最终的静态字段。但是,System.in
,System.out
和System.err
是最终的静态字段,由于遗留原因,必须允许更改方法System.setIn
,System.setOut
和System.setErr
。我们将这些字段称为写保护,以区别于普通的最终字段。
编译器需要以不同于其他最终字段的方式处理这些字段。例如,读取普通的最终字段对同步“免疫”:锁定或易失性读取中涉及的屏障不必影响从最终字段读取的值。由于可以看到写保护字段的值发生变化,因此同步事件应该对它们产生影响。因此,语义要求将这些字段视为用户代码无法更改的普通字段,除非该用户代码在System类中。
编辑:值得一提的是,您可以“破解”最终字段并通过对它们调用setAccessible(true)(或使用Unsafe方法)来设置其值。这些技术在反序列化期间,通过Hibernate和其他框架等使用,但它们有一个限制:在修改之前看到最终字段值的代码不能保证在修改后看到新值。 3个系统字段有什么特别之处它们没有这个限制,因为 它们被编译器以特殊方式处理 。
答案 1 :(得分:3)
System.setIn()
及其朋友setOut()
和setErr()
都委托给未实施Java访问控制规则的本机方法。
答案 2 :(得分:1)
无论是谁而浪费了JLS部分[1]解释它,都只是愚蠢。
这些字段应该简单地删除final
修饰符。它不会破坏二进制兼容性。 [2]
允许用户编写System.out=x
不是问题;毕竟他无论如何都可以做System.setOut(x)
。编译器需要一个特殊的处理来将第一个赋值转换为第二个方法调用。这比当前的方式更好,它扭曲了 读写语义System.out
。
如果我们真的不想看System.out=x
,请将其设为异常,以便编译器不会编译它。
这两个解决方案是简单的句法内容;没有必要为这个愚蠢的小东西打破Java内存模型。
[1] http://java.sun.com/docs/books/jls/third_edition/html/memory.html#17.5.4
[2] http://java.sun.com/docs/books/jls/third_edition/html/binaryComp.html#13.4.9