2013-08-01 22 views
5

クラスのoutオブジェクト(タイプPrintStream)がnull値で初期化されていることがわかりました。 System.out.prinln("");のようなメソッドをどのように呼び出すことができますか? Systemクラスで うち、この方法のように初期化された変数:それは私たちが変数「アウト」を使用する方法、さらに、その後に初期化することはできませんので、コードoutヌルで初期化された変数と、この変数の上に表示を1としてPrintStreamオブジェクトがnullで初期化されていますが、メソッドを呼び出す方法は?

package java.lang; 

public final class System { 
    public final static PrintStream out = nullPrintStream(); 

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

が、最終的です。

+0

が助けになるかもしれないhttp://stackoverflow.com/questions/9454866/out-in-system-out-println – Prabhaker

答えて

4

JVMは、それを初期化しprivate static void initializeSystemClass()メソッドを呼び出します。

setOut0(new PrintStream(new BufferedOutputStream(fdOut, 128), true)); 
setErr0(new PrintStream(new BufferedOutputStream(fdErr, 128), true)); 

これらは2つのネイティブメソッドです:

private static native void setOut0(PrintStream out); 
private static native void setErr0(PrintStream err); 

nice article on itあり

は、次の2行のコードを参照してください。

+1

この記事では、「currentTimeMillis」のトリックについては説明しません。なぜ使用されていますか?何らかの最適化を避けるには? – kan

+0

@kan:基本的なJavaクラスであっても、このような難解なコードを見るのは面白い(時には恐ろしいことです)。 [ 'nullInputStream()'相手が(http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/System.java#1063)を有していますコメントはインライン展開を禁止することを述べていますが、 'null'はコンパイル時にインライン化されず、' null'になる方法は実行時に無関係になります。したがって、[Javaの7版(http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/7-b147/java/lang/System.java/#104)」doesnのもう奇妙な方法があります。 – Holger

6

説明がコメントである:

/** 
* The following two methods exist because in, out, and err must be 
* initialized to null. The compiler, however, cannot be permitted to 
* inline access to them, since they are later set to more sensible values 
* by initializeSystemClass(). 
*/ 

そしてinitializeSystemClass()はnull以外の値に標準ストリームを初期化するために、ネイティブメソッドを使用しています。ネイティブコードは、final宣言された変数を再初期化できます。

+0

私はあなたが以下のコードについて言いたいと思うと思う。private static void initializeSystemClass(){ \t setOut0(new PrintStream(new BufferedOutputStream(fdOut、128)、true)); } プライベート静的ネイティブvoid setOut0(PrintStream out);私は理解していない1つのことは、どのように最終的な変数は2回初期化することができます?? 1つは上記のメソッドから、2回目は私の質問コードです。 – Hits

+0

1ミリ秒未満でこの初期化方法に達するほど速いコンピュータを手に入れてしまえば、うまくいきませんでしたか?または、currentTimeMillis()が値> 0を再実行することが保証されていますか? – Ingo

+1

はい。 currentTimeMillis()は現在の時刻を返しますか? 0は1970年1月1日を意味し、2013年です。最終変数はCで書かれた変数を初期化するネイティブコードなので、2回初期化することができます。もちろん、JVM自体の一部であるこのようなネイティブコードは、Javaコードに適用されるJVMのシックをバイパスすることができます。 –

1

outオブジェクトの場合、gettersetterがあります。 Systemクラスが初期化されます

0

、それはコードがあり、ここで、そのinitializeSystemClass()メソッドを呼び出します。このコードsetOut0で

FileOutputStream fdOut = new FileOutputStream(FileDescriptor.out); 
setOut0(new PrintStream(new BufferedOutputStream(fdOut, 128), true)); 

()System.cで実装ネイティブ関数である:

JNIEXPORT void JNICALL 
Java_java_lang_System_setOut0(JNIEnv *env, jclass cla, jobject stream) 
{ 
    jfieldID fid = 
     (*env)->GetStaticFieldID(env,cla,"out","Ljava/io/PrintStream;"); 
    if (fid == 0) 
     return; 
    (*env)->SetStaticObjectField(env,cla,fid,stream); 
} 

これは、この方法が適切な値にアウト変数を設定するネイティブメソッドsetOut0()を呼び出し、それに渡された引数にSystem.outを設定する標準JNIコードです。

のSystem.outは最終的なもので、それはinitializeSystemClass()に何か他のものに設定することはできませんを意味しますが、ネイティブコードを使用すると、最終的な変数を変更することが可能です。

関連する問題