広告

手を動かして学ぶ Java入門 (クラス継承の超基本)

環境構築不要! ブラウザから直接コードを実行できます。
本記事では、クラスの継承について基本の基本を学びます。

15分くらいで、さくっと終わる記事をめざしています。


シリーズ一覧

続きは近日公開予定!

はじめに

この記事は paiza.IO の「Online Java compiler」を利用しています。
2024/12/17 現在、上記環境の Java バージョンは 18 です。(paiza.IO利用ガイド)

実行したコードは paiza.IO で保存および公開されることがあります。
そのため、個人情報などの機密性の高い情報は、コードとして入力しないようにご注意ください。

詳細は paiza.IO の利用規約およびプライバシーポリシーをご確認ください。

クラスのおさらい

オブジェクト指向プログラミングにおけるクラス(英: class)[注釈 1]は、オブジェクトを生成するための設計図あるいはひな形に相当するものである。抽象データ型の一つ。クラスから生成したオブジェクトの実体のことをインスタンスという。

クラスとは、具体的に いうと…

  • フィールド (変数)
  • メソッド (関数)

この2つが集まったものです。

クラスイメージ図

フィールド(変数) は、数値などを保存しておく箱のようなものです。

メソッド(関数) は、プログラムの実際の処理を書きます。
足し算や引き算などの計算をしたり、その結果を画面に出力したり、などなどです。

例えば、次の Sample クラスでは、

  • value フィールド
  • print メソッド

を宣言しています。

public class Sample {

    private int value = 123;

    public void print() {
        System.out.println("value = " + value);
    }
}

クラスの継承

コンピュータプログラミングにおける継承(けいしょう、英: inheritance)とは、任意のオブジェクトの特性を、他のオブジェクトの特性の基礎にするためのメカニズムと定義されている。

クラスの継承とは、簡単にいうと…

  • ベースとなるクラスの フィールドメソッド
  • それを 引き継いだ 新しいクラスを作る (宣言する)

ことです。

ベースとなるクラスのことは、

  • 基底クラス
  • 親クラス
  • スーパークラス
  • ベースクラス

などと呼ばれます。
この記事では、スーパークラス で表記を統一します。

継承して作った新しいクラスのことは、

  • 派生クラス
  • 子クラス
  • 拡張クラス
  • サブクラス

などと呼ばれます。
この記事では、サブクラス で表記を統一します。

継承イメージ1

イメージとしては、サブクラスの中にスーパークラスを取り込んでいる感じですかね。

目的

継承の主な目的は次の2つです。

  1. 共通するクラス構成 (フィールドとメソッド) を再利用
  2. ポリモーフィズム (多態性) の実現

1つめは比較的イメージしやすいかと思います。

クラスをいくつか作っていたら、似たような構成(フィールドやメソッド) になったので、共通部分を1か所にまとめたい…
そんなときは、スーパークラスに共通部分をまとめて使います。

継承イメージ2


2つめの ポリモーフィズム は、プログラミングにおいてとても大事な概念です。
個人的には、1つめの目的よりこちらのほうが重要だと考えています。

ただ、まだ少し難しい概念だと思いますので、今回の記事では割愛します。
気になるかたは「ポリモーフィズム - Wikipedia」などをご参照ください。

補足

  • クラスの継承は、むやみに使いすぎると「クラス構成が複雑になる」「クラス間の依存度が強くなる」といったデメリットもあります。
  • このあたりの話 (依存度など) も入門としては少し難しいので割愛します…

コード例

具体的なコード例でクラスの継承を見てみましょう。

まずは Counter クラスです。

このクラスは、フィールドとして count を持ちます。
そして、increment メソッドで count を +1 して、print メソッドでその内容を出力します。

public class Counter {
    private int count;

    public void increment() {
        count++;
    }

    public void print() {
        System.out.println("count = " + count);
    }
}

それでは、この Counter クラスを実際に使ってみましょう。
結果がどうなるか予想してから「実行(Ctrl-Enter)」ボタンを押してください。

注意:コードは2ファイルあります。上部のタブで切り替え可能です。

タブ

(表示がおかしいときは「コードの再読み込み」ボタンを押してみてください)

いかがでしたでしょうか? 「出力」のところに

count = 1
count = 2

と表示されたら成功です。

ここまでは、前回までに学習した内容ですね。

さて、次はいよいよクラスの 継承 です。

先ほどの Counter クラスを継承した SubCounter クラスを宣言してみましょう。
継承するには、extends キーワードを使います。

"extend" は直訳すると「拡張する」という意味ですね。
そこに三単現の s をつけて extends となります。

public class SubCounter extends Counter {
}

継承イメージ3

SubCounter クラスの中身は空ですが、これでも Counter クラスを継承できています。
Counter が スーパークラス、SubCounter が サブクラス です。

それでは、この SubCounter クラスを使ってみましょう。
SubCounter クラスは、Counter クラスのメソッドを 引き継いで います。

結果がどうなるか予想してから「実行(Ctrl-Enter)」ボタンを押してください。

注意:コードは3ファイルあります。上部のタブで切り替え可能です。

タブ

(表示がおかしいときは「コードの再読み込み」ボタンを押してみてください)

いかがでしたでしょうか? 「出力」のところに

count = 1
count = 2

と表示されたら成功です。
結果は同じですね。

SubCounter クラスの中身は空です。
しかし、ちゃんと Counter クラスのフィールドとメソッドを引き継いでいるのが確認できました。

宣言

サブクラスの宣言の基本は

  • 通常のクラス宣言 + extends + スーパークラス名

となります。

先ほどの Counter クラスと SubCounter クラスを例に見てみましょう。
Counter クラスがスーパークラス、SubCounter クラスがサブクラスです。

public class SubCounter extends Counter {
^^^^^^^^^^^^^^^^^^^^^^^ <--- 通常のクラス宣言
}
public class SubCounter extends Counter {
                        ^^^^^^^ <--- 継承のためのキーワード
}
public class SubCounter extends Counter {
                                ^^^^^^^^^^ <--- スーパークラス名
}

アクセス修飾子

カプセル化と情報隠蔽を実現するために、Javaではアクセス修飾子を使います。
アクセス修飾子(publicやprivateなど)を使うと、クラスのメンバをどこまで公開するか?どこまで非公開にするか?を制御できます。

フィールドとメソッドのアクセス修飾子は、これまでの記事で次のように学びました。

  • public : クラスの外からアクセスできる
  • private : クラスの外からアクセスできない

アクセス1

表にすると次のようになります。

アクセス修飾子 クラスの外からのアクセス クラス内部からのアクセス
public
private ×

それでは、サブクラスからスーパークラスへのアクセスはどうなるのでしょうか?

アクセス2

正解は、クラスの外からのアクセスと同じになります。

アクセス修飾子 サブクラスからスーパークラスへアクセス
public
private ×

Counter クラスを例に見てみましょう。
先ほどまでとは違い print メソッドはありません。

ポイントは、count フィールドのアクセス修飾子は private であるということです。

public class Counter {
    private int count;

    public void increment() {
        count++;
    }
}

次はサブクラスです。
print メソッドはこちらに宣言しました。

public class SubCounter extends Counter {
    public void print() {
        System.out.println("サブクラスからアクセス : count = " + count);
    }
}

さて、SubCounter クラスから、Counter (スーパークラス) の count フィールドにアクセスしようとしています。

どうなるか予想してから「実行(Ctrl-Enter)」ボタンを押してください。

注意:コードは3ファイルあります。上部のタブで切り替え可能です。

タブ

(表示がおかしいときは「コードの再読み込み」ボタンを押してみてください)

いかがでしたでしょうか? 

SubCounter.java:3: error: count has private access in Counter
        System.out.println("サブクラスからアクセス : count = " + count);
                                                      ^
1 error

とエラーになれば成功です。

"count has private access in Counter" とは、意訳すると

  • count フィールドは Counter クラスの private なフィールドです。(よって外からはアクセスできません)

という感じです。

このように、スーパークラスの private なフィールド(とメソッド) は、サブクラスからはアクセスできません。

【補足】

public と private の中間のような protected というアクセス修飾子もあります。
詳細については下記の記事もご参照ください。


応用問題

【問題】

まずは、下記のプログラムをそのまま「実行(Ctrl-Enter)」してみましょう。
結果はコンパイルエラーになったはずです。

Main.java:7: error: cannot find symbol
        counter.print();
               ^
... 省略 ...

これは、SubCounter クラスに print メソッドが宣言されていないからです。

そこで問題です。
SubCounter クラスに対して、次の2つの修正をいれてください。

  1. Counter クラスを継承させる
  2. incrementDouble メソッドに、カウンタを +2 させる処理を追加

その結果として、プログラムを実行すると、

count = 2
count = 4

と「出力」に表示されるはずです。

それでは、SubCounter クラスを修正してから「実行(Ctrl-Enter)」してみましょう。
(修正するのは SubCounter クラスだけです)

注意:コードは3ファイルあります。上部のタブで切り替え可能です。

タブ

(表示がおかしいときは「コードの再読み込み」ボタンを押してみてください)

無事に、

count = 2
count = 4

と出力されましたでしょうか?

もし解けなかった場合は、下記の回答例をご参照ください。

回答例

【コード】

// Counter クラスを継承してください。
public class SubCounter extends Counter {

    public void incrementDouble() {
        // 必要な処理を追加してください。
        increment();
        increment();
    }
}

※ Main.java, Counter.java は書き換えません。

【出力】

count = 2
count = 4

まとめ

クラスの継承とは、ベースとなるクラスの

  • フィールド
  • メソッド

を引き継いだクラスを作ることをいいます。

ぜひ有効に活用していきたいですね。

次回は「手を動かして学ぶ Java入門 (メソッドのオーバーライド)」になります。


関連記事

ページの先頭へ