Java超|10章のまとめ

クラスは作って終わりではありません。参照でつなぎ、引数で渡し、配列でまとめ、クラスライブラリを活用することで、Javaのオブジェクトの世界は一気に広がります。

10章では、クラスを作る基本からさらに進んで、Javaに用意されているクラスを使う方法や、オブジェクト同士をつないで扱う考え方を学びました。

ここまでくると、Javaのオブジェクト指向は、クラスを定義してオブジェクトを1つ作るだけでは終わりません。

作ったオブジェクトをどう受け渡すのか。
同じオブジェクトを複数の変数でどう扱うのか。
オブジェクト同士をどう関係づけるのか。
複数のオブジェクトをどうまとめて管理するのか。
Javaが用意している便利なクラスをどう活用するのか。

こうした、より実践的な使い方が見えてきます。

ドラゴンボールの世界観でたとえると、1人の戦士だけを見ていた段階から、サイヤ人チーム全体の動きが見えてくる段階です。

悟空という戦士を1人作る。
ベジータという戦士を1人作る。
悟飯という戦士を1人作る。

ここまでは、個別の戦士を扱う段階です。

10章ではさらに進んで、戦士を指し示す登録札を別の場所へ渡したり、どの戦士も指していない状態を表したり、戦士が師匠や仲間を参照したり、メソッドに戦士を渡して処理したり、複数の戦士を名簿のように配列で管理したり、Javaが用意している便利な道具箱を使ったりする考え方を学びました。

つまり10章は、オブジェクトを単体で扱う段階から、オブジェクト同士をつなげて、まとめて、実際のプログラムらしく使う段階へ進むための章です。10章の中心には、クラスライブラリ、クラス型変数、null、クラス型フィールド、クラス型引数、オブジェクト配列を、参照の考え方でつなげて理解する流れがあります。

クラスライブラリを使うと、Javaの道具箱を活用できる

Javaでは、自分でクラスを作るだけでなく、最初から用意されている便利なクラスを使えます。

この便利なクラスの集まりが、クラスライブラリです。

ドラゴンボール風にたとえると、クラスライブラリは、戦士管理本部が用意している巨大な道具箱です。

戦士が任務に出るたびに、スカウター、地図、通信端末、記録帳、計算装置をすべて一から作るのは大変です。

すでに本部に用意されている道具を使えば、任務そのものに集中できます。

Javaでも同じです。

文字列を扱いたいなら String。
文字列をあとから追加・編集したいなら StringBuffer。
文字列を整数に変換したいなら Integer。
数値計算をしたいなら Math。
入力を読み取りたいなら BufferedReader や InputStreamReader。
画面に結果を出したいなら System。

こうした標準クラスを使うことで、すべての機能を自分で作らなくても、実用的な処理を書けるようになります。

クラス主な役割ドラゴンボール風のたとえ
String文字列を扱う任務の巻物を読む
StringBuffer文字列を追加・編集する追記できる作戦記録帳
Integer文字列を整数に変換する数字の札を本物の戦闘力に変える
Math数値計算を行う戦士管理本部の計算道具箱
BufferedReader入力を読み込む通信文を受け取る係
InputStreamReader入力を文字として扱いやすくする届いた情報を読める形に整える係
System画面へ出力する結果を掲示板へ出す係

クラスライブラリを使う良さは、次のように整理できます。

観点内容
手間を減らせるよく使う機能を一から作らなくてよい
コードが読みやすくなる何をしたい処理なのかメソッド名から分かりやすい
実用的な処理を書きやすい入力、変換、計算、表示を組み合わせられる
学習が広がる新しいクラスを調べて使う力がつく

Javaを学ぶうえでは、自分でクラスを作る力も大切です。

ただし、それと同じくらい、用意されたクラスを選んで使う力も大切です。

サイヤ人戦士が、自分の戦闘技だけでなく、本部のスカウターや通信端末を使いこなすことで任務の幅を広げるように、Javaエンジニアもクラスライブラリを使えるようになることで、書けるプログラムの幅が大きく広がります。

クラス型の変数には、同じクラス型の変数を代入できる

10章でとても重要だったのが、クラス型変数の参照のしくみです。

クラス型の変数は、オブジェクトそのものを持っているわけではありません。

そのオブジェクトを指し示す参照を持っています。

ドラゴンボール風にたとえると、変数は戦士本人ではなく、その戦士を指し示す登録札です。

たとえば、goku という変数が1人の SaiyanWarrior オブジェクトを指しているとします。

そこに、vegeta = goku; のように代入すると、戦士が2人に増えるわけではありません。

vegeta も、goku と同じ戦士オブジェクトを指すようになります。

変数名指しているもの
goku同じ SaiyanWarrior オブジェクト
vegeta同じ SaiyanWarrior オブジェクト

この状態では、変数は2つあります。

でも、実体となる戦士オブジェクトは1つです。

ドラゴンボール風にたとえると、1人の戦士に対して、2枚の登録札が向いている状態です。

札が2枚あるからといって、戦士本人が2人に増えるわけではありません。

この考え方は、Javaのオブジェクト指向でとても大切です。

参照が同じなら、状態の変化も同じ対象に見える

複数の変数が同じオブジェクトを指している場合、どちらの変数から見ても同じ実体を見ています。

そのため、片方の変数を通してオブジェクトの状態を変えると、もう一方の変数から見ても、その変化が確認できます。

ドラゴンボール風にたとえると、同じ戦士の訓練記録を、2枚の登録札が指している状態です。

その戦士の戦闘力や気の力が変われば、どちらの札から見ても同じ更新後の記録が見えます。

状態意味
goku と vegeta が同じ戦士を指す実体は1つ
goku から状態を変更する同じ戦士の状態が変わる
vegeta から表示する変更後の状態が見える

ここで大切なのは、変数ごとに別々の戦士を持っているわけではないということです。

変数は別でも、参照先が同じなら、見ているオブジェクトは同じです。

この感覚は、フィールド、仮引数、配列を理解するときにもつながります。

null を代入すると、どのオブジェクトも指さなくなる

クラス型の変数には、null を代入できます。

null は、どのオブジェクトも指していない状態を表します。

ドラゴンボール風にたとえると、戦士を追っていた登録札やスカウターの照準が外れて、今は誰も指していない状態です。

状態意味
warriorRef が戦士を指している戦士オブジェクトを参照している
warriorRef に null を代入するどの戦士も参照していない
null の変数からメソッドを呼ぶ指す相手がいないため問題が起きる

ここで注意したいのは、null は空のオブジェクトではないということです。

null は、オブジェクトが空っぽという意味ではありません。

何も指していない、という意味です。

たとえば、goku がある戦士を指していて、vegeta も同じ戦士を指しているとします。

そのあと goku に null を代入すると、goku はその戦士を指さなくなります。

でも、vegeta がまだその戦士を指しているなら、その戦士オブジェクトはまだ使えます。

変数状態
gokunull になり、どの戦士も指していない
vegetaまだ戦士オブジェクトを指している
戦士オブジェクトvegeta から参照できるので、まだ使える

ドラゴンボール風にたとえると、1枚の登録札が外れても、別の札がまだ戦士を指していれば、その戦士を見失ったことにはなりません。

どの変数からも参照されなくなったオブジェクトは、Javaの管理対象になります。

不要になったオブジェクトは、Javaのガーベッジコレクションによって自動的に回収される可能性があります。

図:10章で学んだ内容の全体像

この図が示していること

この図では、10章で学んだ内容が、1つの SaiyanWarrior オブジェクトを中心につながっていることを表しています。

中央の SaiyanWarrior オブジェクトは、実際に作られた戦士オブジェクトです。

右上の goku と vegeta は、同じ戦士オブジェクトを指す変数として描いています。
これにより、クラス型変数はオブジェクトそのものではなく、参照を持っていることが分かります。

左側の null カードは、変数がどの戦士も指していない状態を表しています。

右側の mentor、partner、leader は、フィールドにクラス型の変数を持たせることで、オブジェクト同士の関係を表せることを示しています。

下部左の train(SaiyanWarrior warrior) は、メソッドの仮引数にクラス型を使い、オブジェクトを受け渡せることを表しています。

下部右の warriors 配列は、複数の戦士オブジェクトをまとめて管理できることを示しています。

左上のクラスライブラリは、Javaが最初から用意している便利なクラスを活用できることを表しています。

ここから分かるのは、10章の内容はバラバラではなく、オブジェクトを参照し、渡し、関係づけ、まとめて扱うという流れでつながっているということです。

フィールドにクラス型の変数を使える

10章では、クラス型の変数をフィールドとして持てることも大切な内容でした。

オブジェクトの中には、int や double のような基本型だけでなく、別のオブジェクトへの参照をフィールドとして持たせることができます。

ドラゴンボール風にたとえると、戦士オブジェクトの中に、師匠、仲間、相棒、所属チームといった別のオブジェクトへのつながりを持たせるようなものです。

たとえば、SaiyanWarrior クラスに mentor というフィールドを用意するとします。

この mentor が別の SaiyanWarrior オブジェクトを指していれば、この戦士の師匠は誰かという関係を表せます。

クラスフィールド意味
SaiyanWarriormentor師匠となる戦士を指す
SaiyanWarriorpartner相棒となる戦士を指す
BattleTeamleader戦闘チームのリーダーを指す
BattleTeammember戦闘チームの戦士を指す

このように、フィールドにクラス型を使うと、オブジェクト同士の関係を自然に表現できます。

これは、オブジェクト指向らしさが強く出る部分です。

単に数値を保存するだけではなく、ものともののつながりを表せる。

これがクラス型フィールドの大きな意味です。

ドラゴンボールでも、戦士を1人ずつ見ているだけでは物語の広がりは見えません。

誰が誰の師匠なのか。
誰が誰と任務に出るのか。
誰が誰を支えているのか。
誰がどのチームに所属しているのか。

こうした関係を見ることで、世界が立体的になります。

Javaのオブジェクト指向も同じで、オブジェクト同士の関係を表せるようになると、プログラムの設計が一気に広がります。

メソッドの仮引数としてクラス型の変数を使える

クラス型の変数は、メソッドの仮引数としても使えます。

つまり、メソッドにオブジェクトを渡して処理できるということです。

ドラゴンボール風にたとえるなら、師匠が、この戦士を修行させる、この戦士を回復させる、この戦士を戦闘チームに加える、といった処理を行うイメージです。

このとき、渡しているのは戦士本人のコピーではありません。

その戦士を指す参照です。

役割内容
呼び出し元戦士オブジェクトを指す変数を持っている
実引数実際にメソッドへ渡す変数
仮引数メソッド側で受け取る変数
渡されるものオブジェクトを指す参照の値

たとえば、train(SaiyanWarrior warrior) というメソッドがあるとします。

この warrior という仮引数は、渡された戦士オブジェクトを指します。

そのため、メソッドの中で warrior.show() を呼べば、その戦士の状態を表示できます。

warrior.setWarrior(...) のような処理をすれば、その戦士の状態を変えることもできます。

処理ドラゴンボール風のたとえ
heal(SaiyanWarrior warrior)指定された戦士を回復する
train(SaiyanWarrior warrior)指定された戦士を修行させる
register(BattleTeam team)指定された戦闘チームを登録する
showStatus(SaiyanWarrior warrior)指定された戦士の状態を表示する

このように、クラス型の仮引数を使えると、オブジェクトを別の処理へ受け渡せるようになります。

これは、実際のJavaプログラムで非常によく使われる考え方です。

オブジェクトを配列でまとめて扱える

10章の中でも、かなり実用的なのがオブジェクト配列です。

オブジェクト配列を使うと、複数のオブジェクトを1つの配列にまとめて管理できます。

ドラゴンボール風にたとえると、悟空、ベジータ、悟飯、ピッコロ系の戦士といった複数の戦士を、戦士名簿としてまとめるようなものです。

配列の位置入っているもののイメージ
warriors[0]悟空系戦士オブジェクトへの参照
warriors[1]ベジータ系戦士オブジェクトへの参照
warriors[2]悟飯系戦士オブジェクトへの参照
warriors[3]ピッコロ系戦士オブジェクトへの参照

ここで大切なのは、配列要素そのものが戦士本人なのではなく、戦士オブジェクトへの参照を持っているということです。

また、オブジェクト配列では、配列を作っただけではオブジェクトはまだ作られていません。

SaiyanWarrior[] warriors;
warriors = new SaiyanWarrior[3];

これは、3人分の席を用意しただけです。

実際の戦士を作るには、各要素に new SaiyanWarrior() を代入する必要があります。

warriors[0] = new SaiyanWarrior();
warriors[1] = new SaiyanWarrior();
warriors[2] = new SaiyanWarrior();

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

手順内容ドラゴンボール風のたとえ
1配列を作る戦士を並べる席を用意する
2各要素にオブジェクトを作るそれぞれの席に戦士を配置する
3配列要素からメソッドを呼ぶ各戦士に指示を出す
4for 文でまとめて処理する戦士名簿を順番に確認する

配列を使えば、for 文と組み合わせて全員に同じ処理を行いやすくなります。

たとえば、全員の状態を表示する。
全員に訓練値を設定する。
全員の名前を確認する。
全員を順番に任務へ登録する。

このような処理が書きやすくなります。

これは、オブジェクトを1人ずつ扱う段階から、チームとしてまとめて扱う段階へ進む大切な一歩です。

図:戦士オブジェクトを配列・引数・フィールドでつなぐ

この図が示していること

この図では、オブジェクトが配列、フィールド、仮引数によってつながる様子を表しています。

左側の warriors 配列は、複数の戦士オブジェクトへの参照を持っています。

warriors[0] は悟空系戦士オブジェクト、warriors[1] はベジータ系戦士オブジェクト、warriors[2] は悟飯系戦士オブジェクトを指しています。

右上の mentor や partner は、フィールドにクラス型を使うことで、別の戦士オブジェクトを指せることを表しています。

これにより、悟飯系戦士が悟空系戦士を師匠として持つような関係を表現できます。

右下の train(SaiyanWarrior warrior) は、メソッドの仮引数として戦士オブジェクトへの参照を受け取ることを表しています。

これにより、特定の戦士をメソッドへ渡して処理できます。

下部の null は、どの戦士も指していない状態を表します。

ここから分かるのは、配列、フィールド、仮引数は、それぞれ違う場所に見えても、すべてオブジェクトへの参照を使ってつながっているということです。

10章の内容はすべて「参照」でつながっている

10章の学習内容は、一見すると別々の話に見えるかもしれません。

クラスライブラリ。
クラス型変数の代入。
null。
クラス型フィールド。
クラス型引数。
オブジェクト配列。

でも、実はこれらはすべて参照の考え方でつながっています。

学んだ内容参照とのつながり
クラス型変数の代入同じオブジェクトを別の変数でも指せる
nullどのオブジェクトも指していない状態を表す
クラス型フィールドオブジェクトの中に別オブジェクトへの参照を持てる
クラス型引数メソッドへオブジェクトへの参照を渡せる
オブジェクト配列配列要素がオブジェクトへの参照を持てる
クラスライブラリ用意されたクラスのオブジェクトやメソッドを使う

ドラゴンボール風にたとえると、10章は戦士本人だけを見る章ではありません。

戦士を指す登録札。
戦士同士のつながり。
戦士を任務へ渡す流れ。
戦士名簿としてまとめる仕組み。
本部の道具箱を使う方法。

こうした、サイヤ人チーム全体の動きが見えるようになる章です。

10章で押さえたいポイント一覧

10章で学んだ内容を、ドラゴンボールの世界観で整理すると次のようになります。

学んだ内容ドラゴンボール風のたとえ大事な理解
クラスライブラリの利用戦士管理本部の道具箱を使う既存の便利なクラスを活用できる
同じクラス型の代入同じ戦士を複数の登録札が指すオブジェクト本体のコピーではない
null の代入どの戦士も指していない札参照が切れた状態
フィールドにクラス型を使う師匠や仲間を戦士が覚えているオブジェクト同士の関係を表せる
仮引数にクラス型を使う指定された戦士を修行させるオブジェクトをメソッドへ渡せる
オブジェクト配列戦士名簿で複数人を管理する複数のオブジェクトをまとめて扱える

この表を見ると、10章の中心には、オブジェクトは単独で終わらないという考え方があることが分かります。

オブジェクトは、変数から参照されます。
別の変数からも参照されます。
フィールドの中に参照として持たれます。
メソッドへ引数として渡されます。
配列の要素としてまとめられます。

このように、オブジェクトはプログラムの中でつながりながら使われます。

サンプルプログラム:参照・引数・配列をまとめて見る

ここでは、10章の内容をイメージしやすくするために、参照、クラス型引数、オブジェクト配列を組み合わせたサンプルプログラムを見てみます。

class SaiyanWarrior
{
    private String name;
    private int battlePower;
    private SaiyanWarrior mentor;

    public SaiyanWarrior(String n, int b)
    {
        name = n;
        battlePower = b;
        mentor = null;
    }

    public void setMentor(SaiyanWarrior m)
    {
        mentor = m;
    }

    public void train()
    {
        battlePower += 500;
    }

    public void show()
    {
        System.out.println("名前:" + name);
        System.out.println("戦闘力:" + battlePower);

        if (mentor != null) {
            System.out.println("師匠:" + mentor.name);
        }
        else {
            System.out.println("師匠:未設定");
        }
    }
}

class Main
{
    public static void powerUp(SaiyanWarrior warrior)
    {
        warrior.train();
    }

    public static void main(String[] args)
    {
        SaiyanWarrior goku = new SaiyanWarrior("悟空", 9000);
        SaiyanWarrior vegeta = new SaiyanWarrior("ベジータ", 8500);
        SaiyanWarrior gohan = new SaiyanWarrior("悟飯", 7000);

        gohan.setMentor(goku);

        SaiyanWarrior anotherGoku = goku;

        powerUp(anotherGoku);

        SaiyanWarrior[] warriors = new SaiyanWarrior[3];
        warriors[0] = goku;
        warriors[1] = vegeta;
        warriors[2] = gohan;

        for(int i = 0; i < warriors.length; i++){
            warriors[i].show();
        }
    }
}

このサンプルでは、10章の大切な考え方がいくつも出てきます。

まず、goku、vegeta、gohan という3つのクラス型変数が、それぞれ別の SaiyanWarrior オブジェクトを指しています。

次に、gohan.setMentor(goku); によって、悟飯の mentor フィールドが悟空オブジェクトを指すようになります。

これは、フィールドにクラス型を使って、戦士同士の関係を表している例です。

さらに、次の行では、同じオブジェクトを別の変数でも指しています。

SaiyanWarrior anotherGoku = goku;

この時点で、anotherGoku と goku は同じ悟空オブジェクトを指しています。

そのあと、次のようにメソッドへ渡しています。

powerUp(anotherGoku);

powerUp(SaiyanWarrior warrior) の仮引数 warrior は、anotherGoku が指している悟空オブジェクトへの参照を受け取ります。

そして warrior.train(); を実行するため、悟空オブジェクトの戦闘力が上がります。

最後に、warriors 配列へ3人の戦士を入れています。

SaiyanWarrior[] warriors = new SaiyanWarrior[3];
warriors[0] = goku;
warriors[1] = vegeta;
warriors[2] = gohan;

この配列は、3つの SaiyanWarrior オブジェクトへの参照をまとめて管理しています。

for 文で show() を呼び出すことで、全員の状態を順番に表示できます。

コードの要素10章の内容
anotherGoku = goku同じクラス型の代入
mentorクラス型フィールド
powerUp(SaiyanWarrior warrior)クラス型の仮引数
warriors 配列オブジェクト配列
mentor = null参照先がない状態
for 文複数オブジェクトの順番処理

このように、参照、フィールド、引数、配列は、別々の知識ではなく、1つのプログラムの中で自然につながります。

オブジェクト指向の広がりが見えてくる

10章の内容が分かると、Javaのコードの見え方がかなり変わります。

それまでは、クラスを作る、オブジェクトを作る、メソッドを呼ぶ、という単体の流れが中心でした。

10章ではそこから進んで、オブジェクトがどのように使い回されるのかが見えてきます。

見えてくること内容
オブジェクトは参照で扱われる変数はオブジェクトそのものではなく参照を持つ
同じオブジェクトを複数の変数が見られる代入によって参照先を共有できる
参照を切ることもできるnull を代入すると、どのオブジェクトも指さない
オブジェクト同士を関係づけられるフィールドにクラス型を持たせられる
オブジェクトをメソッドへ渡せる仮引数にクラス型を使える
複数のオブジェクトをまとめられるオブジェクト配列を使える
標準クラスも活用できるクラスライブラリを使える

ドラゴンボール風にたとえると、1人の戦士の能力だけを見ていた段階から、サイヤ人チーム全体の関係性が見えてくる段階です。

誰が誰を指しているのか。
誰が誰とつながっているのか。
誰を任務へ渡すのか。
複数の戦士をどう名簿で管理するのか。
本部の道具箱をどう使うのか。

こうした視点が入ることで、オブジェクト指向の世界が一気に広がります。

図:10章の知識は実践的なJavaコードにつながる

この図が示していること

この図では、10章の学習内容が実践的なJavaコードへつながっていく流れを表しています。

左側では、クラスを作る、オブジェクトを作る、メソッドを呼ぶという基礎を示しています。

中央では、参照の共有、null、クラス型フィールド、クラス型引数、オブジェクト配列、クラスライブラリという10章の重要内容をまとめています。

右側では、それらの知識が、入力、変換、計算、オブジェクト管理、チーム処理、表示といった実践的なプログラムへつながることを表しています。

ここから分かるのは、10章の内容は単なる文法の追加ではなく、Javaで実用的なプログラムを作るための土台になるということです。

実践的なJavaコードへ進むための土台

10章で学んだ内容は、どれも実際のJavaプログラムでよく使われます。

たとえば、入力された文字列を Integer で数値に変換し、Math で計算する。

複数の戦士オブジェクトを配列に入れ、for 文で順番に表示する。

メソッドへ戦士オブジェクトを渡して、状態を変更する。

フィールドに別のオブジェクトを持たせて、関係を表す。

必要がなくなった参照には null が関係することもあります。

実践での場面10章の知識
入力値を変換して計算するクラスライブラリ
同じデータを複数の場所で扱う参照の共有
使わない参照を外すnull
オブジェクト同士の関係を持たせるクラス型フィールド
オブジェクトを処理に渡すクラス型仮引数
複数データを一覧管理するオブジェクト配列

この章で学んだ内容は、次の段階へ進むための大切な橋渡しです。

配列、コレクション、継承、ポリモーフィズムなどを学ぶときにも、10章の参照の感覚が土台になります。

ここで押さえておきたい重要ポイント

10章で特に大切なポイントを整理します。

ポイント内容
クラスライブラリを使えるJavaが用意した便利なクラスを活用できる
クラス型変数は参照を持つオブジェクトそのものではなく、指す情報を持つ
同じクラス型の変数を代入できる同じオブジェクトを複数の変数で指せる
null は参照先なしを表すどのオブジェクトも指していない状態
フィールドにクラス型を使えるオブジェクトの中に別オブジェクトへの参照を持てる
仮引数にクラス型を使えるメソッドへオブジェクトを渡せる
オブジェクト配列を使える複数のオブジェクトをまとめて管理できる

ドラゴンボールの世界で考えると、10章は戦士を1人ずつ作る段階から、戦士たちをつなげて動かす段階へ進む内容でした。

戦士を指す登録札を使う。
同じ戦士を複数の札が指す。
札を外して、誰も指さない状態にする。
戦士が師匠や仲間を持つ。
戦士をメソッドへ渡して修行させる。
複数の戦士を名簿に並べて管理する。
そして、戦士管理本部の道具箱のように、Javaのクラスライブラリを活用する。

この感覚が身につくと、Javaのオブジェクト指向はかなり自然に読めるようになります。

オブジェクトは、ただ作って終わりではありません。

参照でつながり、引数で渡され、フィールドに保持され、配列でまとめられながら、プログラムの中で役割を持って動いていきます。