6

以下は、java.lang.System クラス (JDK バージョン 1.6) のコードです。

public final static PrintStream out = nullPrintStream(); //out is set to 'null'

private static PrintStream nullPrintStream() throws NullPointerException {
    if (currentTimeMillis() > 0) {
        return null;
    }
    throw new NullPointerException();
}

コードを記述System.out.println("Something");すると、「out」が「null」に設定されている場合でも NullPointerException が発生しないのはなぜですか

とにかく、システムクラスのout次のメソッドを介して設定されますsetOut

public static void setOut(PrintStream out) {
     checkIO();
     setOut0(out);
 }

なぜJLSがnullPrintStreamメソッドを必要とするのですか?

4

3 に答える 3

8

を見てくださいprivate static void initializeSystemClass()- このメソッドは物事を開始するために呼び出されsetOut0()nativeメソッドであるを呼び出します。これにより、あるべき場所に結び付けStreamられます。

そのため、フィールドが実際にはそうでないように見え ても、コードによって変更されます。public static finalnative

編集

OPが尋ねるでは、なぜJLSがnullPrintStreamメソッドを必要とするのですか?

static finalこれは Java コンパイラに関係しています。コンパイル時にフィールドが何か定数に割り当てられている場合、フィールドを「インライン化」しますnull。コンパイラは、実際にはフィールドへの各参照を定数に置き換えます。

Streamこれにより、オブジェクトがへの参照を保持しなくなり、 への参照が保持されるため、初期化が中断されますnull。メソッドの戻り値にストリームを割り当てると、インライン化が防止されます。

汚いハックと呼ぶ人もいるかもしれません。Bismarck の「JDK はソーセージのようなものです。それが作られているのを見ないのが最善です」という誤った引用です。

于 2013-03-22T08:46:32.677 に答える
2

これは、System.out クラスが初期化される方法です。

次の方法もあります。

 private static native void setOut0(PrintStream out);

次のメソッドで呼び出されます。

private static void initializeSystemClass() {
于 2013-03-22T08:42:52.773 に答える
2

System.in、out、および err は、ネイティブ コードから JVM によって管理されます。nullPrintStream() を使用したこの魔法全体は、javac がこれらのフィールドをインライン化しないようにするためにありました。Java 7以降、次のようになります

public final static PrintStream out = null;
于 2013-03-22T08:47:47.203 に答える