Systemクラスのクラス変数について
〜JavaAPIを読んで見るシリーズ〜 個人メモ用
以外に奥が深かったよSystem.out.printlnの巻
Systemクラスにて宣言されているクラス変数について、色々わからなかったので調べてみました。
public final static InputStream in = null;
public final static PrintStream out = null;
public final static PrintStream err = null;
【疑問点1】
・System.out.println の変数 out には null が入っているはずなのに
なぜprintlnメソッドを呼び出せるのか
・変数outはfinal修飾子であり、nullで初期化しているのであとから変数を
代入することは不可能なはず?
■final修飾子にあとから値を代入する例
public class TEST1_final {
public final static String value1 = null;
public static void main(String[] args) {
value1 = "aaa";
System.out.println(value1);
}
}
■実行結果
Exception in thread "main" java.lang.Error: Unresolved compilation problem:
final フィールド TEST1_final.value1 には代入できません
at javaAPI_練習用/TEST1.TEST1_final.main(TEST1_final.java:6)
やはりエラーでした。
というか、System.inとかSystem.outを出力したら変数の中身ある…
public class TEST1 {
public static void main(String[] args) {
System.out.println(System.in);
System.out.println(System.out);
System.out.println(System.err);
}
}
■実行結果
java.io.BufferedInputStream@448139f0
java.io.PrintStream@7cca494b
java.io.PrintStream@7ba4f24f
いつ誰が代入したの…
【調べた結果まとめ】
同Systemクラス内にinitializeSystemClassというメソッドがあります。
このメソッド内にて値を設定しています。
ちなみに、このメソッドはJVM初期化時に動いているらしいです。
private static void initializeSystemClass() {
…(省略)
setIn0(new BufferedInputStream(fdIn));
setOut0(newPrintStream(fdOut, props.getProperty("sun.stdout.encoding")));
setErr0(newPrintStream(fdErr, props.getProperty("sun.stderr.encoding")));
■定義元(同Systemクラス内)
private static native void setIn0(InputStream in);
private static native void setOut0(PrintStream out);
private static native void setErr0(PrintStream err);
(native修飾子がついているので、このメソッドは別言語で実装されていて、そこで値を設定している。)
【疑問への回答】
・Systemクラスの各final変数は同クラス内のinitializeSystemClassメソッドを使って値を代入している。
・低レイヤーな他言語(多分Cとか)で代入している。
・initializeSystemClassはJVMの初期化辺りのタイミングで呼ばれる。
※呼ばれるタイミングについては理解がまだ曖昧です。。調べるの時間かかりそうなので後回し
以上
【参考】
https://stackoverflow.com/questions/19173965/why-are-the-printstream-out-and-inputstream-in-null
https://ytetsuwo.hatenadiary.org/entry/20110816