LoginSignup
40
55

More than 5 years have passed since last update.

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

Posted at

概要

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

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

HelloWorld.java
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と書くことができます。

以下の2行は全く同じ意味
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クラスであることがわかります。

System.outの宣言
public static final PrintStream out

試しにSystem.outPrintStream型の変数に代入してみましょう。

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)以外でリテラル表記できるのは、プリミティブ型(intboolean等)の値とnullだけです。

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

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

文字列リテラルを使用しない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に限らず、インスタンスがどこでどのように生成されるのかを知っておくことは重要なので、知らないと困る度は、★★☆(2)としておきます。

さいごに

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


  1. Java以外の言語では、文字列以外のクラスをリテラルで表記できることも珍しくないです(正規表現リテラルや日付リテラルなど) 

  2. このコードは、StringクラスのJavaDocからの引用です。 

40
55
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
40
55