17.

Javaの継承

編集

本稿は Java の継承に関する記事です。継承とは、既存のクラス (親クラス・スーパークラス) が持つフィールド・メソッドを、新しいクラス (子クラス・サブクラス) でそのまま引き継いで利用する仕組みです。共通ロジックを 1 箇所にまとめ、差分だけ子クラスに書く設計を可能にします。

継承の構文

class 子クラス名 extends 親クラス名 {
    // 子クラス固有の処理 / オーバーライド
}

継承の具体例

// 親クラス
public class Animal {
    protected final String name;

    public Animal(String name) {
        this.name = name;
    }

    public String greet() {
        return name + ": hello";
    }
}

// 子クラス
public class Dog extends Animal {
    public Dog(String name) {
        super(name);  // 親のコンストラクタ呼び出し
    }

    @Override
    public String greet() {
        return super.greet() + ", woof!";
    }
}

Animal a = new Dog("Pochi");
System.out.println(a.greet()); // Pochi: hello, woof!

継承で出来ること

仕組み概要
フィールド・メソッドの継承親クラスの protected / public なメンバを子側でそのまま使える
メソッドのオーバーライド同じシグネチャで挙動を上書きする (@Override を付ける)
多態性 (ポリモーフィズム)親クラスの型変数で子インスタンスを扱える
抽象クラス・抽象メソッド共通ロジック + 必須実装を子へ強制
final で禁止クラスやメソッドの継承・オーバーライドを禁止

Java の継承ルール

  • クラスの多重継承は不可 (extends は 1 つだけ)。複数の振る舞いを取り込みたい場合はインタフェースimplements する
  • すべてのクラスは暗黙的に java.lang.Object を継承
  • コンストラクタは継承されない。子側で自分のコンストラクタを定義する
  • 子のコンストラクタ先頭で親のコンストラクタが必ず呼ばれる (明示しなければ super())
  • private メンバは継承されるが、子からは直接アクセスできない
  • static メンバも継承されるが、本質的にはクラス共有なのでオーバーライドの代わりに「隠蔽 (hiding)」になる
  • インタフェースは多重実装可。Java 8 以降は default メソッドで実装も持てる

アクセス修飾子と継承可視性

修飾子同一クラス同一パッケージ子クラス
public
protected×
(無指定 / package-private)××
private×××

オーバーライドのルール

  • シグネチャ (メソッド名・引数の型と数) が親と一致すること
  • 戻り値は親と同じか、共変な (より狭い) 型でも可
  • アクセス修飾子は親と同等以上の公開度 (狭めるのは不可)
  • チェック例外は親が宣言しているもの以下に限る
  • @Override アノテーションをつけてコンパイラチェックを利用

継承と合成 (Composition) の使い分け

判断軸継承合成 (フィールドとして保持)
関係性「〜は〜である (is-a)」「〜は〜を持つ (has-a)」
結合度強い弱い
差分実装の柔軟性制限される柔軟
テスト容易性親に依存して難しくなりがちモック差し替えしやすい

近年は「Composition over Inheritance」(継承より合成) の方針が主流です。継承は本当に is-a 関係がある場合のみ使い、ふるまいの差し替えはインタフェース+実装注入を活用します。

注意点

  • final クラス / final メソッドは継承・オーバーライド禁止 (String は final クラス)
  • 深い継承階層は理解しづらく壊れやすい。2〜3 階層に留めるのが目安
  • サブクラスから親のprotected フィールドを書き換える設計は脆い。getter / setter 経由が安全
  • equals / hashCode の継承はサブクラスで再定義が必要なケースが多い
  • 差分プログラミング (Diff Programming) の手段としての継承の濫用は強い密結合を生み、変更コストを上げる

関連

編集
Post Share
子ページ

子ページはありません

同階層のページ
  1. 基本的なルール
  2. データ型
  3. 変数
  4. 定数
  5. 配列
  6. コレクション(List,Set,Queue)
  7. Map(連想配列)
  8. 演算子
  9. 条件分岐
  10. 繰り返し制御文
  11. クラス
  12. メソッド
  13. インスタンス化
  14. コンストラクタ
  15. staticキーワード
  16. オーバーロード
  17. 継承
  18. オーバーライド
  19. this
  20. super
  21. パッケージ
  22. アクセス修飾子
  23. 抽象クラス・メソッド
  24. インターフェース
  25. カプセル化
  26. データベース接続
  27. セッション
  28. ファイル入出力
  29. ラムダ式