概要
「Hello world」を読み解くが長くなったので、具体的な処理の部分の解説はこちらに書くことにしました。
前の投稿のコードを再掲しておきます。
この投稿では、この「Hello world」のなかの、具体的な処理が記述されている行を解説します。
public class HelloWorld {
public static void main(String[] args) {
System.out.println("hello, world");
}
}
System.out.println("hello, world");
また、各項目には私の独断で「知らないと困る度」をつけました。★が多いほど知っておいた方がよいということになります。
System
は、java.lang.System
クラスを指す (知らないと困る度: ★★☆)
Javaでは、暗黙的に(何も記述しなくても)import java.lang.*
されます。
つまり、java.lang
パッケージに属するクラスは、import
宣言を記述しなくても参照することができます。
そのため、java.lang.System
クラスは、単にSystem
と書くことができます。
System.out.println("Hello world");
java.lang.System.out.println("Hello world");
知らないと困る度は?
java.lang.
を省略しないことは通常あり得ません。
しかし、java.lang
パッケージに属しているということを知らないと、JavaDoc を調べるときなどに困るので、省略した記法だということは知っておきましょう。
知らないと困る度は、**★★☆(2)**としておきます。
out
は、System
クラスのstatic
なフィールド (知らないと困る度: ★☆☆)
System
クラスのJavaDocを見てみましょう。
以下の3つのstatic
なフィールドが定義されていることが説明されています。
フィールド名 | 説明 |
---|---|
err | 「標準」エラー出力ストリームです。 |
in | 「標準」入力ストリームです。 |
out | 「標準」出力ストリームです。 |
上記のとおり、System.out
は、System
クラスのstatic
なフィールドを指します。
『「標準」出力ストリーム』とは、「標準出力」に繋がっている「ストリーム」のことです。(「標準出力」と「ストリーム」の説明は、ここでは割愛します)
一般的には、フィールドをpublic
にするよりも、取得メソッド(いわゆるgetter)を経由させるほうがよい設計とされています。
また、上記のフィールドはJavaの慣習からするとかなり異質な名前となっています。
おそらく、利便性のためにこのような特殊な設計となっているものと考えられます。
さて、out
フィールドの説明を見ると、このフィールドはPrintStream
クラスであることがわかります。
public static final PrintStream out
試しにSystem.out
をPrintStream
型の変数に代入してみましょう。
java.io.PrintStream ps = System.out; // System.outをpsに代入
ps.println("Hello world"); // psのprintlnメソッドの呼び出し
結果はもちろん、1行でSystem.out.println("hello, world");
と書いたときと変わりません。
知らないと困る度は?
「System.out.println
」は、Javaプログラムから標準出力に値を出力する際のイディオムとなっています。
そのため、out
が具体的に何なのかを知らなくても特に困ることはないでしょう。
とはいえ基本的なところなので、知ってて欲しいという気持ちを込めて、知らないと困る度は**★☆☆(1)**としておきます。
"Hello world"は、Stringインスタンス生成の糖衣構文(知らないと困る度: ★★☆)
String
クラスのJavaDocを見てみましょう。以下のように説明されています。
String クラスは文字列を表します。Java プログラム内の "abc" などのリテラル文字列はすべて、このクラスのインスタンスとして実行されます。
String
クラスは、数多あるJavaのクラスの中でも断トツの好待遇をされているクラスといえます。
Java言語において1、リテラルで表記できるクラスはString
クラスだけです。
文字列(String
)以外でリテラル表記できるのは、プリミティブ型(int
やboolean
等)の値とnull
だけです。
さて、ここで「リテラルってなんだっけ?」となった方も多いのではないかと思います。
簡単に説明すると、『リテラルとは、「ソースコードに直接記述された値」のこと』です。
リテラルという用語がいまいちピンとこない方も、以下のコード2を見ればその重要性が垣間見えるのではないでしょうか?
char data[] = {'a', 'b', 'c'};
String str = new String(data);
// 上記は以下のコードと同じ
String str = "abc";
もしも文字列リテラルがなかったら、「任意の値のString
インスタンスを得る」ためには、「char配列を引数としたコンストラクタの呼び出しを記述する」必要があります。
Stringは多用されるため、いちいちこんな記述していたら面倒すぎます。
「糖衣構文」とは、このような「面倒なコード」の記述を簡略化するための文法上の仕組みです。
つまり、「String
インスタンスの生成」には、文字列リテラルという糖衣構文が用意されているということになります。
知らないと困る度は?
任意の値のString
インスタンスが必要な場合は、文字列リテラルで生成します。
むしろ、必要もないのにコンストラクタの呼び出しで、インスタンスを生成してはいけません。
(byte
配列からの文字列生成などでは、String
のコンストラクタを使用することもあります)
しかし、文字列リテラルで記述していても、実質的にはnew String(...)
しているということ(つまりString
インスタンスを生成している)を知っておく必要はあるでしょう。
String
に限らず、インスタンスがどこでどのように生成されるのかを知っておくことは重要なので、知らないと困る度は、**★★☆(2)**としておきます。
さいごに
「Hello world」を読み解くの最後で、この投稿の内容をHelloWorld.java
に反映したコードを書いてみたので、そちらもご覧ください。
-
Java以外の言語では、文字列以外のクラスをリテラルで表記できることも珍しくないです(正規表現リテラルや日付リテラルなど) ↩
-
このコードは、
String
クラスのJavaDocからの引用です。 ↩