Java System.setIn()重新指定final System.in
可能重复:Java System.setIn()重新指定final System.in,java,Java,可能重复: 虽然我做了很多次都没有注意到,但我突然想到:System.setIn()正在重新分配static finalSystem.in 我错过什么了吗?如何重新分配最终字段。通常,最终静态字段不能修改。但是System.in、System.out和System.err是最终的静态字段,由于遗留原因,必须允许通过System.setIn、System.setOut和System.setErr方法更改这些字段。我们将这些字段称为写保护字段,以区别于普通的最终字段 编译器需要将这些字段与其他最终
虽然我做了很多次都没有注意到,但我突然想到:
System.setIn()
正在重新分配static finalSystem.in
我错过什么了吗?如何重新分配最终字段。通常,最终静态字段不能修改。但是
System.in
、System.out
和System.err
是最终的静态字段,由于遗留原因,必须允许通过System.setIn
、System.setOut
和System.setErr
方法更改这些字段。我们将这些字段称为写保护字段,以区别于普通的最终字段
编译器需要将这些字段与其他最终字段区别对待。例如,对普通最终字段的读取对同步“免疫”:锁或易失性读取中涉及的屏障不必影响从最终字段读取的值。由于写保护字段的值可能会发生变化,因此同步事件应该会对其产生影响。因此,语义要求将这些字段视为不能由用户代码更改的普通字段,除非该用户代码位于系统类中
编辑:值得一提的是,您可以通过对最终字段调用setAccessible(true)(或使用不安全的方法)来“黑客”最终字段并设置其值。Hibernate和其他框架等在反序列化过程中使用了这些技术,但它们有一个限制:在修改之前看到final字段值的代码不能保证在修改之后看到新值这3个系统字段的特殊之处在于它们不受此限制,因为编译器以特殊方式对它们进行处理。setIn()和它的朋友setOut()和setErr()都委托给本机方法,没有强制执行Java访问控制规则的地方。不管是谁做了这件事并浪费了JLS部分[1]来解释,都是愚蠢的 这些字段只需删除
final
修饰符即可。它不会破坏二进制兼容性。[2]
允许用户写入System.out=x
不是问题;不管怎样,他都能做系统。出发(x)
。编译器需要特殊处理才能将第一个赋值转换为第二个方法调用。这比当前的方式要好,它扭曲了System.out
的读写语义
如果我们真的不想看到System.out=x
,请将其设置为异常,这样编译器就不会编译它
这两种解决方案都是简单的语法材料;没有必要为了这个愚蠢的小东西而破坏Java内存模型
[1]
[2] @david:老实说,我找了一会儿,但这个问题没有出现,可能是因为它指的是系统。out@dimitrisli-我已更新链接问题的标题,以便更容易找到。。。当这个问题以重复的形式结束时。嗯。。JVM出于遗留原因进行的特殊处理。如果要复制java语言规范的整个部分,那么值得注意的是setAccessible(true)将private/public修饰符更改为public。实际上,您必须进入“修改器”字段并更改修改器。您必须使用反射来获得修改器,然后使用反射来更改修改器,我记得。我已经有一段时间没做了——上一次我不得不破解最后一个字段是几个月前,我只是复制了它。