英文:
Why is here working and here not working?
问题
public class Main {
public static final PrintStream x = null;
public static void main(String[] args) {
/*Line 8*/ System.out.println("Da");
/*Line 9*/ x.println("Da");
}
}
为什么第8行能正常工作,即使“out”引用为null,在第9行,我创建了另一个与引用“out”相同的引用(类型为“PrintStream”的静态final,值为null),为什么不起作用并且我得到“NullPointerException”?
英文:
public class Main {
public static final PrintStream x = null;
public static void main(String[] args) {
/*Line 8*/ System.out.println("Da");
/*Line 9*/ x.println("Da");
}
}
Why is line 8 working, even if the "out" reference is null, and on line 9, where I made another reference same as the reference "out" (static final of type "PrintStream" with a value of null) is not working and I get "NullPointerException"?
答案1
得分: 5
我认为你的第二张图片展示了 java.lang.System
的代码片段。
我认为你在问,“为什么 System.out.println
能够正常工作,尽管 System.out
被声明为 final
并且初始化为 null
”。
答案是…… 魔法!
在 JVM 初始化过程中存在一些深奥的魔法,它会重新分配非空值给 System.in
、System.out
和 System.err
。事实上,甚至在 Java 语言规范中也提到了这些字段的特殊性(如果你感兴趣,可以查看17.5.4)。
类似的魔法也用于使 System.setOut(...)
等方法正常工作。
依我看,最好的做法是相信它能正常工作……而不去深究为什么。
作为推论,你尝试实现类似操作不起作用的原因是因为你的 x
字段表现如预期。它被初始化为 null
,并且保持这个状态。这里没有什么魔法。你的代码并不“特殊”。
(值得一提的是,在某些情况下,可以使用反射来修改 final
字段的值。但这是一个不好的想法。首先,Java 语言规范仔细地没有规定在这样做时会发生什么,参见17.5.3。)
英文:
I think your second image is showing a snippet of the code of java.lang.System
.
And I think you are asking "how come System.out.println
works despite System.out
being final
and initialized to null
".
The answer is ... magic!!
There is some deep dark magic in the JVM initialization that reassigns non-null values to System.in
, System.out
and System.err
. Indeed, the specialness of these fields even gets a mention in the Java Language Specification (17.5.4 if you are curious).
Similar magic is used to make System.setOut(...)
and friends work.
IMO, it is best to just trust that it works ... and not ask how.
And the corollary is that the reason your attempt to do something similar doesn't work is that your x
field is behaving as expected. It has been initialized to null
, and it stays that way. No magic going on here. Your code isn't "special".
(For what it is worth, in some contexts it is possible to use reflection to modify the value of a final
field. But it is a bad idea. For a start, the JLS carefully does not specify what happens when you do this; see 17.5.3.)
答案2
得分: 4
System.out
是一个有些神奇的字段。尽管它被声明为 final
并且被初始化为 null
,但它实际上具有非空值。
这是因为 JVM
对此(以及其他一些)字段有特殊处理。
你无法通过纯粹的 Java 代码来复现这种行为,你需要使用不安全的魔法。
英文:
System.out
is somewhat magical field. Despite the fact that it is final
and initialized with null
it actually have non-null value.
It happens because JVM
have special treatment for that (and some other) fields.
You can't reproduce such behavior with pure java, you need to use unsafe magic.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论