为什么这里能够正常工作,而这里却不能正常工作?

huangapple go评论74阅读模式
英文:

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.inSystem.outSystem.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.

huangapple
  • 本文由 发表于 2020年10月2日 15:33:38
  • 转载请务必保留本文链接:https://go.coder-hub.com/64167728.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定