首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >System.in:“最终”的System.out、System.in和System.err?

System.in:“最终”的System.out、System.in和System.err?
EN

Stack Overflow用户
提问于 2011-05-10 22:16:49
回答 7查看 4.7K关注 0票数 79

System.out被声明为public static final PrintStream out

但是您可以调用System.setOut()来重新分配它。

哈?如果是final,这怎么可能呢?

(同样的观点也适用于System.inSystem.err)

更重要的是,如果您可以更改公共静态最终字段,那么就final为您提供的保证(如果有的话)而言,这意味着什么?(我从来没有意识到也没有想到System.in/out/err表现为final变量)

EN

回答 7

Stack Overflow用户

回答已采纳

发布于 2011-05-10 22:28:44

JLS 17.5.4 Write Protected Fields

通常情况下,不能修改最终的静态字段。但是,System.inSystem.outSystem.err是最终的静态字段,由于遗留原因,必须允许System.setInSystem.setOutSystem.setErr方法对其进行更改。我们将这些字段称为写保护字段,以将它们与普通的最终字段区分开来。

编译器需要将这些字段与其他最终字段区别对待。例如,对普通final字段的读取对同步是“免疫的”:锁或易失性读取中涉及的屏障不必影响从final字段读取的值。由于写保护字段的值可能会发生更改,因此同步事件应该会对它们产生影响。因此,语义规定,除非用户代码在System类中,否则这些字段应被视为不能被用户代码更改的普通字段。

顺便说一句,实际上您可以通过反射对final字段调用setAccessible(true) (或使用Unsafe方法)来改变这些字段。这些技术在反序列化、Hibernate和其他框架等过程中使用,但它们有一个限制:在修改之前已经看到final字段的值的代码不能保证在修改后看到新值。有问题的字段的特殊之处在于,它们没有这种限制,因为编译器以特殊的方式处理它们。

票数 56
EN

Stack Overflow用户

发布于 2011-05-10 22:18:52

Java使用原生方法来实现setIn()setOut()setErr()

在我的JDK1.6.0_20上,setOut()看起来像这样:

代码语言:javascript
复制
public static void setOut(PrintStream out) {
    checkIO();
    setOut0(out);
}

...

private static native void setOut0(PrintStream out);

你仍然不能“正常地”重新赋值final变量,即使在这种情况下,你也不能直接重新赋值这个字段(即你仍然不能编译"System.out = myOut")。本机方法允许一些在常规Java中根本不能做的事情,这就解释了为什么对本机方法有限制,比如要求applet必须签名才能使用本机库。

票数 29
EN

Stack Overflow用户

发布于 2011-05-10 22:21:15

为了扩展Adam所说的内容,这里是impl:

代码语言:javascript
复制
public static void setOut(PrintStream out) {
    checkIO();
    setOut0(out);
}

并且setOut0被定义为:

代码语言:javascript
复制
private static native void setOut0(PrintStream out);
票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/5951464

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档