System.out.println("hello, world")を読み解く

## 概要
[「Hello world」を読み解く][link-hello]が長くなったので、具体的な処理の部分の解説はこちらに書くことにしました。

[前の投稿][link-hello]のコードを再掲しておきます。
この投稿では、この「Hello world」のなかの、具体的な処理が記述されている行を解説します。

```java:HelloWorld.java
public class HelloWorld {

  public static void main(String[] args) {
    System.out.println("hello, world");
  }

}
```

```java:具体的な処理が記述されている行
System.out.println("hello, world");
```

また、各項目には**私の独断で**「知らないと困る度」をつけました。★が多いほど知っておいた方がよいということになります。


### `System`は、`java.lang.System`クラスを指す (知らないと困る度: ★★☆)

Javaでは、暗黙的に(何も記述しなくても)`import java.lang.*`されます。
つまり、`java.lang`パッケージに属するクラスは、`import`宣言を記述しなくても参照することができます。

そのため、`java.lang.System`クラスは、単に`System`と書くことができます。

```java:以下の2行は全く同じ意味
System.out.println("Hello world");
java.lang.System.out.println("Hello world");
```

#### 知らないと困る度は?

`java.lang.`を省略しないことは通常あり得ません。
しかし、`java.lang`パッケージに属しているということを知らないと、[JavaDoc][link-java_lang] を調べるときなどに困るので、省略した記法だということは知っておきましょう。

知らないと困る度は、**★★☆(2)**としておきます。


### `out`は、`System`クラスの`static`なフィールド (知らないと困る度: ★☆☆)

[`System`クラスのJavaDoc][link-system]を見てみましょう。
以下の3つの`static`なフィールドが定義されていることが説明されています。

|フィールド名 | 説明 |
|-----|--------------------------|
| err | 「標準」エラー出力ストリームです。 |
| in  | 「標準」入力ストリームです。      |
| out | 「標準」出力ストリームです。      |

上記のとおり、`System.out`は、`System`クラスの`static`なフィールドを指します。
『「標準」出力ストリーム』とは、「標準出力」に繋がっている「ストリーム」のことです。(「標準出力」と「ストリーム」の説明は、ここでは割愛します)

一般的には、フィールドを`public`にするよりも、取得メソッド(いわゆるgetter)を経由させるほうがよい設計とされています。
また、上記のフィールドはJavaの慣習からするとかなり異質な名前となっています。
おそらく、利便性のためにこのような特殊な設計となっているものと考えられます。

さて、`out`フィールドの説明を見ると、このフィールドは[`PrintStream`][link-printstream]クラスであることがわかります。

```java:System.outの宣言
public static final PrintStream out
```

試しに`System.out`を`PrintStream`型の変数に代入してみましょう。

```java: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][link-string]を見てみましょう。以下のように説明されています。

> String クラスは文字列を表します。Java プログラム内の "abc" などのリテラル文字列はすべて、このクラスのインスタンスとして実行されます。

`String`クラスは、数多あるJavaのクラスの中でも断トツの好待遇をされているクラスといえます。
Java言語において[^literal_o]、リテラルで表記できるクラスは`String`クラスだけです。
文字列(`String`)以外でリテラル表記できるのは、プリミティブ型(`int`や`boolean`等)の値と`null`だけです。

さて、ここで「リテラルってなんだっけ?」となった方も多いのではないかと思います。
簡単に説明すると、『リテラルとは、「ソースコードに直接記述された値」のこと』です。

リテラルという用語がいまいちピンとこない方も、以下のコード[^string_new]を見ればその重要性が垣間見えるのではないでしょうか?

```java:文字列リテラルを使用しないStringインスタンスの生成例
char data[] = {'a', 'b', 'c'};
String str = new String(data);

// 上記は以下のコードと同じ
String str = "abc";
```

もしも文字列リテラルがなかったら、「任意の値の`String`インスタンスを得る」ためには、「char配列を引数としたコンストラクタの呼び出しを記述する」必要があります。
Stringは多用されるため、いちいちこんな記述していたら面倒すぎます。

「糖衣構文」とは、このような「面倒なコード」の記述を簡略化するための文法上の仕組みです。
つまり、「`String`インスタンスの生成」には、文字列リテラルという糖衣構文が用意されているということになります。

#### 知らないと困る度は?
任意の値の`String`インスタンスが必要な場合は、文字列リテラルで生成します。
むしろ、必要もないのにコンストラクタの呼び出しで、インスタンスを生成してはいけません。
(`byte`配列からの文字列生成などでは、`String`のコンストラクタを使用することもあります)

しかし、文字列リテラルで記述していても、実質的には`new String(...)`しているということ(つまり`String`インスタンスを生成している)を知っておく必要はあるでしょう。

`String`に限らず、インスタンスがどこでどのように生成されるのかを知っておくことは重要なので、知らないと困る度は、**★★☆(２)**としておきます。


## さいごに

[「Hello world」を読み解く][link-hello]の最後で、この投稿の内容を`HelloWorld.java`に反映したコードを書いてみたので、そちらもご覧ください。



[link-hello]:https://qiita.com/pale2f/items/7431f7c31862225df395
[link-java_lang]:https://docs.oracle.com/javase/jp/7/api/index.html?java/lang/package-summary.html
[link-system]:https://docs.oracle.com/javase/jp/7/api/index.html?java/lang/System.html
[link-printstream]:https://docs.oracle.com/javase/jp/7/api/index.html?java/io/PrintStream.html
[link-string]:https://docs.oracle.com/javase/jp/7/api/index.html?java/lang/String.html

[^literal_o]: Java以外の言語では、文字列以外のクラスをリテラルで表記できることも珍しくないです(正規表現リテラルや日付リテラルなど)
[^string_new]: このコードは、[`String`クラスのJavaDoc][link-string]からの引用です。