Java超|クラスから実体を作るしくみ

クラスという設計図から悟空という実体を生み出し、名前・戦闘力・流派の印・流派名を設定する。Javaのオブジェクト指向は、new で戦士オブジェクトが登場した瞬間から動き出します。

Javaのオブジェクト指向では、クラスを作っただけでは、まだ実際に動く存在は生まれていません。

クラスは、ひとことでいうと設計図です。
ドラゴンボールの世界観でたとえるなら、クラスは「サイヤ人という戦士は、名前、戦闘力、流派の印、流派名などの情報を持つ」という共通ルールをまとめた戦士の設計図です。

ただし、設計図があるだけでは、悟空やベジータや悟飯がプログラムの中に登場したことにはなりません。

そこから new を使って実体を作り、名前、戦闘力、流派の印、流派名を設定し、その情報を画面に表示する。
この流れがつながって、はじめてクラスを使ったJavaプログラムとして動き出します。

この記事では、クラスを宣言し、オブジェクトを作り、フィールドに値を入れ、画面に表示するまでの流れを、ドラゴンボールの世界観で整理していきます。

クラスを利用するとはどういうことか

クラスを学び始めると、まず class の書き方に注目しやすいです。
もちろん、クラスを宣言することはとても大切です。

しかし、クラスは書いて終わりではありません。

クラスは、そこからオブジェクトを作って利用してこそ意味を持ちます。

Javaでクラスを利用する流れは、次のようになります。

手順内容ドラゴンボールでのイメージ
1クラスを宣言するサイヤ人戦士の設計図を作る
2クラスからオブジェクトを作成する設計図から悟空という戦士を登場させる
3オブジェクトのメンバにアクセスする悟空の名前、戦闘力、流派情報に触れる
4値を表示したり使ったりする悟空の情報をスカウター画面に表示する

つまり、クラスは設計図、オブジェクトは実体、メンバアクセスは実体の情報に触れる操作です。

ドラゴンボールでたとえると、
「サイヤ人戦士」という設計図を作り、そこから「悟空」という戦士を登場させ、その戦士の名前、戦闘力、流派の印、流派名を設定し、最後にスカウター画面へ表示する流れです。

この流れが見えると、クラスはただの文法ではなく、プログラムの中で使える部品として理解しやすくなります。

図:クラスからオブジェクトが生まれる流れ

この図が示していること

この図は、クラスが設計図であり、new によってその設計図からオブジェクトが作られる流れを示しています。

左側の Saiyan クラスは、まだ具体的な悟空ではありません。
name、power、styleMark、styleName という情報欄を持つ、共通の設計図です。

中央の new Saiyan() によって、その設計図から実体が作られます。
右側の goku オブジェクトには、実際の名前、戦闘力、流派の印、流派名が入ります。

ここから分かる大事なことは、クラスとオブジェクトは別々に覚えるものではなく、設計図から実体を作るという1本の流れでつながっているということです。

設計図と実体を1本の流れで見る

クラスとオブジェクトは、別々に暗記するよりも、1本の流れとして見ると理解しやすくなります。

たとえば、Saiyan クラスを作るとします。

このクラスには、サイヤ人戦士に共通する情報として name、power、styleMark、styleName を持たせます。

フィールド意味例
name戦士の名前悟空
power戦闘力9000
styleMark流派を表す印亀
styleName流派名亀仙流

ただし、この段階ではまだ具体的な悟空はいません。

name という名前欄、power という戦闘力欄、styleMark という流派の印欄、styleName という流派名欄を用意しただけです。
そこから goku というオブジェクトを作ると、その goku に対して具体的な値を入れられるようになります。

考え方内容ドラゴンボールでのイメージ
クラスどんな情報を持つかを決めるサイヤ人戦士の設計図
オブジェクトその情報に実際の値を持つ登場した悟空
メンバアクセスオブジェクトの中の情報に触れる悟空の登録情報を見る、変更する

ドラゴンボールで言えば、Saiyan クラスはサイヤ人登録用の設計図です。
goku オブジェクトは、その設計図から作られた実際の悟空です。

goku.name、goku.power、goku.styleMark、goku.styleName は、その悟空の名前欄、戦闘力欄、流派の印欄、流派名欄にアクセスしている状態です。

流派の表記を整理する

この記事では、流派を表す情報として styleMark と styleName を使います。

styleMark は、流派を短く表す印です。
styleName は、流派の正式な名前です。

styleMarkstyleName
亀亀仙流
鶴鶴仙流
武武泰斗流
塔カリン流
魔ピッコロ魔族流
神神流(ナメック流)
惑惑星戦士流
界北の界王流

今回の Sample1.java では、悟空の流派を次のように扱います。

フィールド値
styleMark亀
styleName亀仙流

つまり、goku.styleMark に 亀 を入れ、goku.styleName に 亀仙流 を入れることで、悟空が亀仙流の戦士として登録されていることを表します。

実際に動くプログラムで確認する

ここでは、クラスの宣言、オブジェクトの作成、フィールドへの値の代入、表示までをまとめたプログラムを確認します。

ファイル名:Sample1.java

class Saiyan
{
    String name;
    int power;
    String styleMark;
    String styleName;
}

class Sample1
{
    public static void main(String[] args)
    {
        Saiyan goku;
        goku = new Saiyan();

        goku.name = "悟空";
        goku.power = 9000;
        goku.styleMark = "亀";
        goku.styleName = "亀仙流";

        System.out.println("戦士の名前は" + goku.name + "です。");
        System.out.println("戦闘力は" + goku.power + "です。");
        System.out.println("流派の印は「" + goku.styleMark + "」です。");
        System.out.println("流派名は" + goku.styleName + "です。");
    }
}

このプログラムには、クラスを使う基本の流れがまとまっています。

処理内容
Saiyan クラスを宣言するサイヤ人戦士の設計図を作る
Saiyan goku;オブジェクトを扱うための変数を用意する
goku = new Saiyan();実体となるオブジェクトを作る
goku.name = 悟空;名前を設定する
goku.power = 9000;戦闘力を設定する
goku.styleMark = 亀;流派の印を設定する
goku.styleName = 亀仙流;流派名を設定する
System.out.println設定した値を表示する

このように、クラスを使う流れは、設計図を作る、実体を作る、値を入れる、値を使う、という順番で進みます。

プログラムの前半では設計図を作っている

最初に書かれているのは Saiyan クラスです。

class Saiyan
{
    String name;
    int power;
    String styleMark;
    String styleName;
}

ここでは、サイヤ人戦士が持つ情報として name、power、styleMark、styleName を定義しています。

フィールド意味
name戦士の名前
power戦闘力
styleMark流派の印
styleName流派名

この段階では、まだ悟空という戦士は作られていません。

あくまで、「サイヤ人戦士なら名前、戦闘力、流派の印、流派名を持つ」という設計図を作っている状態です。

name、power、styleMark、styleName は、まだ具体的な値ではありません。
これから作るオブジェクトが持つ情報の種類を表しています。

ドラゴンボールで言えば、まだ悟空本人は戦場に立っていません。
戦闘データ端末に、「サイヤ人戦士には名前欄、戦闘力欄、流派の印欄、流派名欄が必要」と登録しただけの段階です。

main メソッドから処理が始まる

次に Sample1 クラスがあります。

class Sample1
{
    public static void main(String[] args)
    {
        ...
    }
}

Javaのプログラムは、main メソッドから実行が始まります。

このファイルには、Saiyan クラスと Sample1 クラスの2つがあります。
そのうち、実際に最初に動くのは main メソッドを持つ Sample1 クラスです。

クラス役割
Saiyan悟空オブジェクトを作るための設計図
Sample1プログラムを開始する実行用クラス

Saiyan クラスは設計図として使われます。
Sample1 クラスは、実際に処理を進める入口です。

1つのファイルの中に複数のクラスがあっても、どこから処理が始まるのかを意識すると、プログラム全体の見通しがよくなります。

オブジェクトを作成している部分

main メソッドの中では、まず次の2行があります。

Saiyan goku;
goku = new Saiyan();

この2行は、オブジェクト作成の基本です。

1行目では、Saiyan 型の変数 goku を宣言しています。

Saiyan goku;

これは、Saiyan オブジェクトを扱うための変数を用意している状態です。

ドラゴンボールで言えば、悟空という戦士を管理するための登録札を用意したようなものです。
ただし、この時点では、まだ実体の悟空オブジェクトは作られていません。

2行目では、新しい Saiyan オブジェクトを作り、それを goku に代入しています。

goku = new Saiyan();

ここで new が登場します。

new は、クラスという設計図から、実際のオブジェクトを作るための重要な命令です。

コードイメージ
Saiyan goku;悟空を扱うための登録札を用意する
goku = new Saiyan();設計図からサイヤ人の実体を作り、goku で扱えるようにする

ここで大切なのは、goku はオブジェクトそのものではなく、Saiyan オブジェクトを参照する変数だということです。

少しやわらかく言うと、goku は作られた戦士オブジェクトを指し示す名前です。
そのため、goku.name、goku.power、goku.styleMark、goku.styleName のように書くことで、goku が指しているオブジェクトの中身にアクセスできます。

フィールドに具体的な値を入れている部分

次に、フィールドへ値を代入しています。

goku.name = "悟空";
goku.power = 9000;
goku.styleMark = "亀";
goku.styleName = "亀仙流";

ここでは、goku が参照しているオブジェクトの name、power、styleMark、styleName に具体的な値を入れています。

アクセス入る値意味
goku.name悟空戦士の名前
goku.power9000戦闘力
goku.styleMark亀流派の印
goku.styleName亀仙流流派名

この処理によって、ただの Saiyan オブジェクトだったものが、「名前は悟空、戦闘力は9000、流派の印は亀、流派名は亀仙流の戦士」として具体的な状態を持ちます。

ここで使っている goku.name、goku.power、goku.styleMark、goku.styleName のような書き方が、メンバアクセスです。

基本形は次の形です。

変数名.フィールド名

変数名.フィールド名 の形で、参照しているオブジェクトの中にあるフィールドへアクセスします。

ドラゴンボールでたとえるなら、goku という登録札を通して、悟空の名前欄、戦闘力欄、流派の印欄、流派名欄に値を入れている状態です。

図:メンバアクセスで値を入れる流れ

以下の条件でイラストを作成してください。

カラーイラスト、16:9横長。白と青を基調にした学習教材風デザイン。ドラゴンボール風のアニメ調。背景は青く光るスカウター解析室。中央に大きなオブジェクトカードを配置する。

カードのタイトルは「goku が参照する Saiyan オブジェクト」とする。カード内に小さな悟空アイコンを入れ、その横に4つのフィールド欄を表示する。

フィールド欄には次の文字を入れる。
「name = 悟空」
「power = 9000」
「styleMark = 亀」
「styleName = 亀仙流」

画面左側にはコード断片として「goku.name = "悟空";」「goku.power = 9000;」「goku.styleMark = "亀";」「goku.styleName = "亀仙流";」を表示する。左側のコードから中央のフィールド欄へ矢印を伸ばし、「メンバアクセス」と表示する。

悟空アイコンは小さな戦士アイコンとして描く。ワインレッドの道着を着せ、右胸に「亀」の丸いマークを入れる。文字は読みやすく、背景やキャラクターと重ならないようにする。

この図が示していること

この図は、goku.name、goku.power、goku.styleMark、goku.styleName のようなメンバアクセスによって、オブジェクトの中にあるフィールドへ値を入れている様子を示しています。

goku は、Saiyan オブジェクトを参照する変数です。
そのため、goku.name と書くと、goku が指しているオブジェクトの name フィールドにアクセスできます。

同じように、goku.power と書くと戦闘力欄に、goku.styleMark と書くと流派の印欄に、goku.styleName と書くと流派名欄にアクセスできます。

この図から分かることは、フィールドの値はクラスそのものに直接入れているのではなく、new で作られたオブジェクトの中に入れているということです。

表示している部分を見る

最後に、設定した値を画面に表示しています。

System.out.println("戦士の名前は" + goku.name + "です。");
System.out.println("戦闘力は" + goku.power + "です。");
System.out.println("流派の印は「" + goku.styleMark + "」です。");
System.out.println("流派名は" + goku.styleName + "です。");

ここでは、goku.name、goku.power、goku.styleMark、goku.styleName に入っている値を取り出して表示しています。

実行結果は次のようになります。

戦士の名前は悟空です。
戦闘力は9000です。
流派の印は「亀」です。
流派名は亀仙流です。

この表示によって、オブジェクトに入れた値が正しく使われていることが分かります。

ここまで来ると、クラス、オブジェクト、フィールド、メンバアクセス、表示が1本の流れとしてつながります。

要素プログラム内での表れ方役割
クラスSaiyanサイヤ人の設計図
オブジェクト作成new Saiyan()実体を作る
参照変数goku作られた実体を扱う名前
フィールドname, power, styleMark, styleNameオブジェクトが持つ情報
メンバアクセスgoku.name, goku.power, goku.styleMark, goku.styleNameオブジェクト内の情報に触れる
表示System.out.println値を画面に出す

このプログラムで押さえたいポイント

このプログラムには、クラス利用の基本が入っています。

ポイント内容
クラス宣言Saiyan クラスで設計図を作る
オブジェクト作成new Saiyan() で実体を作る
変数goku がそのオブジェクトを参照する
メンバアクセスgoku.name、goku.power、goku.styleMark、goku.styleName で情報に触れる
表示設定した値を画面に出す

この表を見ながらコードを読むと、1行ごとの役割が整理しやすくなります。

特に大事なのは、クラスを宣言しただけでは値を入れる場所がまだないという点です。

値を入れるには、new でオブジェクトを作る必要があります。
そして、作られたオブジェクトに対して、goku.name、goku.power、goku.styleMark、goku.styleName の形でアクセスします。

styleMark と styleName を分ける理由

今回のプログラムでは、流派に関する情報を styleMark と styleName の2つに分けています。

String styleMark;
String styleName;

styleMark は、流派を一文字で表す印です。
styleName は、流派の正式な名前です。

たとえば、悟空の場合は次のようになります。

フィールド値役割
styleMark亀道着やカードに表示する短い印
styleName亀仙流流派の正式名称

ドラゴンボールの世界観で考えると、styleMark は道着の胸に入っている印のようなものです。
一方、styleName は、その印が表す正式な流派名です。

つまり、亀 という印だけでも雰囲気は伝わりますが、亀仙流 という名前も持たせることで、プログラム上でより分かりやすく流派を扱えるようになります。

オブジェクトは1つだけでなく複数作れる

Sample1.java では、オブジェクトを1つだけ作っています。

Saiyan goku;
goku = new Saiyan();

ただし、同じクラスからオブジェクトはいくつでも作成できます。

たとえば、悟空だけでなく、ベジータや悟飯も作りたい場合は、考え方として次のようになります。

Saiyan goku;
goku = new Saiyan();
goku.name = "悟空";
goku.power = 9000;
goku.styleMark = "亀";
goku.styleName = "亀仙流";

Saiyan vegeta;
vegeta = new Saiyan();
vegeta.name = "ベジータ";
vegeta.power = 8500;
vegeta.styleMark = "惑";
vegeta.styleName = "惑星戦士流";

Saiyan gohan;
gohan = new Saiyan();
gohan.name = "悟飯";
gohan.power = 7000;
gohan.styleMark = "魔";
gohan.styleName = "ピッコロ魔族流";

このようにすると、同じ Saiyan クラスから作られた3つのオブジェクトが、それぞれ別の値を持てます。

変数namepowerstyleMarkstyleName
goku悟空9000亀亀仙流
vegetaベジータ8500惑惑星戦士流
gohan悟飯7000魔ピッコロ魔族流

クラスは1つでも、作られるオブジェクトは複数にできます。

ドラゴンボールで言えば、サイヤ人という設計図は1つでも、そこから悟空、ベジータ、悟飯のような複数の戦士を登場させられるということです。

ただし、この記事で具体的に扱うサンプルプログラムは Sample1.java のみです。
複数オブジェクトの話は、クラスの利用がどのように広がるかを理解するためのイメージとして押さえておくと十分です。

コンパイルするとクラスファイルが複数できる

Sample1.java には、2つのクラスが書かれています。

ソースファイル内のクラス役割
Saiyanサイヤ人の設計図
Sample1main メソッドを持つ実行用クラス

そのため、コンパイルすると対応するクラスファイルも2つ作られます。

ソースファイル内のクラス作成されるクラスファイル
SaiyanSaiyan.class
Sample1Sample1.class

Sample1.java をコンパイルしたときに class ファイルが2つできても、不思議ではありません。

Javaでは、ソースファイルの中に書かれているクラスごとに class ファイルが作られます。

ここは入門段階で少し混乱しやすいところです。

Sample1.java という1つのファイルをコンパイルしているのに、Saiyan.class と Sample1.class ができます。
これは、ファイル数ではなく、クラスごとに class ファイルが作られるためです。

実行するときの見方

プログラムを実行するときは、main メソッドを持つ Sample1 クラスを実行します。

Saiyan クラスは、オブジェクトを作るための設計図です。
Sample1 クラスは、実際に処理を始める入口です。

この違いを整理すると、次のようになります。

クラス役割ドラゴンボールでのイメージ
Saiyanオブジェクトの設計図サイヤ人戦士の登録フォーマット
Sample1プログラムの開始地点悟空を登場させて表示する管理画面

実行時には Sample1 の main メソッドが動きます。
その中で Saiyan オブジェクトを作り、値を入れて表示しています。

つまり、Saiyan は材料を定義するクラス、Sample1 はその材料を使って処理を進めるクラスです。

図:Sample1.java の役割分担と class ファイル

この図が示していること

この図は、Sample1.java の中に Saiyan クラスと Sample1 クラスがあることを示しています。

Saiyan クラスは、サイヤ人の設計図です。
Sample1 クラスは、main メソッドを持つ実行用のクラスです。

また、コンパイルすると Saiyan.class と Sample1.class が作られることも示しています。

この図から分かることは、1つのソースファイルに複数のクラスが書かれている場合、クラスごとに class ファイルが作られるということです。

さらに、Saiyan クラスには name、power、styleMark、styleName というフィールドがあり、それらの情報を持つオブジェクトを作るための設計図になっていることも分かります。

クラスを作る人と利用する人が分かれることもある

クラスの便利なところは、設計図を作る人と、それを利用する人が分かれても使えることです。

たとえば、次のように役割を分けられます。

役割内容ドラゴンボールでのイメージ
クラスを作る人Saiyan クラスを設計するサイヤ人登録システムの設計者
クラスを使う人Saiyan からオブジェクトを作り、表示や管理を行う登録システムを使って戦士を管理する担当者

クラスが分かりやすく設計されていれば、別の人でもそのクラスを使ってプログラムを書きやすくなります。

つまりクラスは、自分だけが使うものではありません。
他の処理からも利用できる部品として作れるところに価値があります。

ドラゴンボールで言えば、サイヤ人の登録フォーマットを一度きちんと作っておけば、別の管理者もそのフォーマットを使って悟空、ベジータ、悟飯の情報を登録できるようになる、というイメージです。

オブジェクト指向の入口として大事なこと

クラスやオブジェクトをもとにプログラムを組み立てる考え方は、オブジェクト指向と呼ばれます。

最初は難しく感じるかもしれませんが、入門段階では次の流れを押さえれば大丈夫です。

流れ内容ドラゴンボールでのイメージ
クラスで設計図を作るどんな情報を持つかを決めるサイヤ人戦士の登録フォーマットを作る
オブジェクトで実体を作るnew で具体的な存在を作る悟空を1人登場させる
メンバにアクセスするフィールドへ値を入れる名前、戦闘力、流派の印、流派名を設定する
値を使う画面に表示するスカウター画面に情報を出す

ドラゴンボールで言えば、次のような流れです。

サイヤ人戦士という型を作る。
悟空という実体を生み出す。
悟空の名前、戦闘力、流派の印、流派名を設定する。
その情報を画面に表示する。

この感覚がつかめると、これから学ぶメソッド、コンストラクタ、継承、ポリモーフィズムも、「設計図と実体」という土台の上にあることが見えやすくなります。

クラスは設計図。
オブジェクトは、その設計図から作られた実体。
new は、設計図から実体を生み出す合図。
変数.フィールド名 は、その実体の中にある情報へアクセスする方法。

今回の例では、goku.name、goku.power、goku.styleMark、goku.styleName によって、悟空オブジェクトの中にある情報へアクセスしました。

この4つがつながると、Javaのオブジェクト指向はかなり見通しよく理解できるようになります。