System.out.println()
解題Revised: Jan./8th/2001
単純なスタンドアロンアプリケーションでは、標準出力への出力は次のように書く:
//行末で改行なし System.out.print(); //行末で改行付き System.out.println();
これは任意のクラスで自由に使える。何故だろうか? System.out
は System
クラスのメンバ変数呼び出しであり、 print()
メソッドは PrintStream
クラスである。そんなことが許される理由は何だろうか?
System
System
クラスは java.lang
パッケージに含まれる。全てのクラスでは java.lang
パッケージは自動的にインポートされている。したがって、 public
宣言が付いた System
クラスは自由に使える。
但し、 System
クラスはインスタンス化できない。System.java
のソースコードを確認すると、コンストラクタが private
宣言されていた。
System
クラスはどこからでも参照できるが、インスタンス化は出来ないようになっている。
out
out
は System
クラスで定義されたメンバ変数(フィールド)であり、既に開いている標準出力ストリームを意味する。修飾子は public final static PrintStream
であり、 static
宣言されているので、 System
クラスをインスタンス化しなくとも、クラス名で直接アクセスできる。
また、この変数の型は PrintStream
クラス型である。このクラスは java.io
パッケージに含まれるが、 System
クラスでは冒頭でこのクラスをインポートしているので、この使用法に関して問題はない。
この変数は、既に開いている標準出力ストリームをオブジェクトとして参照する。この使用法が変更されないように、 final
宣言がされており、事実上のパラメータとなっている。
print()
, println()
これらのメソッドは PrintStream
クラスで定義されているので、 PrintStream
型で定義されている変数 out
をオブジェクトとしたメソッドになれる。
オブジェクトを明示する為に、参照型変数の代入をしてみよう。ここでは、 PrintStream
型の変数 out
を、別の PrintStream
型の変数に代入している。System
クラスのメンバ変数として定義されている out
は、任意のクラスから System.out
で参照できる:
PrintStream obj = System.out; obj.println();
PrintStream
型変数である obj
に対して、参照のコピーが行われている。参照先は Syste.out
、すなわち標準出力ストリームである。この標準出力ストリーム・オブジェクトのメソッド println()
を呼び出しているわけである。
ここでは、オブジェクトを明示する為に新たに変数を定義して代入したが、直接メソッド呼び出しすれば、次のようになるわけだ:
System.out.println();
実際には、 System.in
, System.out
を標準入出力デバイスに関連付けるために、システムのネイティブな函数を利用している。順番としては、空の入出力ストリーム System.in
, System.out
を定義し、これをネイティブメソッドの中で PrintStream
型の標準入出力ストリームと関連付けている。標準入出力を要求すると、 Java VM はネイティブな函数 (DLL: Dynamic Link Library) を通して、OSのカーネルへ対応するデバイスの制御を受け渡しているわけだ。