Java入門 #21 - 継承(extends)の基本

入門 | 10分 で読める | 2026.05.02

公式ドキュメント

このシリーズについて

「Java入門」シリーズの第21回です。本記事では**継承(Inheritance)**の基本を学びます。

継承とは

継承は、既存のクラス(スーパークラス / 親クラス)の機能を引き継いで、新しいクラス(サブクラス / 子クラス)を定義する仕組みです。

// Java 21 - スーパークラス
public class Animal {
 protected String name;

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

 public void eat() {
 System.out.println(name + " is eating.");
 }
}
// Java 21 - サブクラス
public class Dog extends Animal {
 public Dog(String name) {
 super(name); // スーパークラスのコンストラクタを呼び出す
 }

 public void bark() {
 System.out.println(name + " is barking: Woof!");
 }
}

DogAnimal を継承しているため、eat() メソッドと name フィールドを持ちます。さらに独自の bark() を追加しています。

ポイント: 継承を使うと、共通の機能を親クラスにまとめ、個別の機能だけを子クラスに追加できます。コードの重複を減らし、保守性が向上します

extends キーワード

サブクラスを定義するには extends を使います。

public class サブクラス extends スーパークラス {
 // フィールド、コンストラクタ、メソッド
}
用語意味
スーパークラス(親クラス)継承元のクラス
サブクラス(子クラス)継承先のクラス。スーパークラスの機能 + 独自の機能を持つ

Java は単一継承のみサポートします。複数のクラスを同時に継承(extends A, B)することはできません。

注意: Java では1つのクラスしか継承できませんが、後に学ぶ インターフェース(interface)は複数実装できます。

super() でスーパークラスのコンストラクタを呼び出す

サブクラスのコンストラクタは、最初にスーパークラスのコンストラクタを呼び出す必要があります。

// Java 21 - super() の明示的な呼び出し
public class Cat extends Animal {
 private int lives;

 public Cat(String name, int lives) {
 super(name); // Animal のコンストラクタを呼び出す
 this.lives = lives;
 }

 public void meow() {
 System.out.println(name + " is meowing: Meow!");
 }
}

super(name)コンストラクタの最初の行に書く必要があります。書かない場合、コンパイラが自動で super() (引数なし)を挿入しますが、スーパークラスに引数なしコンストラクタがないとコンパイルエラーになります。

ヒント: super() はスーパークラスのコンストラクタ、this() は同じクラスの別のコンストラクタを呼び出します。どちらも最初の行に書く必要があるため、両方を同時に使うことはできません。

フィールド・メソッドの継承

サブクラスはスーパークラスの public / protected フィールドとメソッドを自動的に持ちます。

// Java 21 - 継承されたメソッドを使う例
public class Main {
 public static void main(String[] args) {
 Dog dog = new Dog("Pochi");
 dog.eat(); // Animal から継承したメソッド
 dog.bark(); // Dog 独自のメソッド
 }
}

実行結果:

Pochi is eating.
Pochi is barking: Woof!

Dog クラスには eat() の定義はありませんが、Animal を継承しているため呼び出せます。

メソッドオーバーライド

サブクラスでスーパークラスのメソッドを**上書き(Override)**することができます。

// Java 21 - メソッドオーバーライドの例
public class Bird extends Animal {
 public Bird(String name) {
 super(name);
 }

 @Override
 public void eat() {
 System.out.println(name + " is pecking seeds.");
 }

 public void fly() {
 System.out.println(name + " is flying.");
 }
}

Birdeat()Animaleat() を上書きしています。@Override アノテーションを付けることで、オーバーライドの意図を明示し、コンパイラがチェックしてくれます。

ポイント: @Override は省略可能ですが、必ず付けましょう。メソッド名のタイポ(eat のつもりで eatt と書いてしまう等)をコンパイル時に検出できます。

オーバーライドのルール

ルール説明
メソッド名・引数が同じ異なるとオーバーロード(別メソッド扱い)
戻り値の型は同じか、共変戻り値を子クラスの型に変更するのは許可(共変戻り値型)
アクセス修飾子は同等以上protected → public は OK。public → private は NG
static / final メソッドは不可static は継承しない。final は上書き禁止

アクセス修飾子と継承の関係

スーパークラスのフィールド・メソッドがサブクラスから見えるかどうかは、アクセス修飾子で決まります。

修飾子同じクラス同じパッケージサブクラス(別パッケージ)外部
private
(なし / package-private)
protected
public

継承で重要なポイント:

  • private フィールド・メソッドはサブクラスから直接アクセスできない(継承はされているが見えない)
  • protected はサブクラスからアクセスできるが、外部には非公開
  • public はどこからでもアクセス可能
// Java 21 - アクセス修飾子の違い
public class Animal {
 private String secret = "秘密"; // サブクラスから見えない
 protected String name; // サブクラスから見える
 public void eat() { /* ... */ } // どこからでも呼べる
}

public class Dog extends Animal {
 public void printInfo() {
 // System.out.println(secret); // コンパイルエラー(private)
 System.out.println(name); // OK(protected)
 }
}

注意: protected は同じパッケージ内からもアクセスできます。完全に継承先だけに公開したい場合でも、パッケージを分けない限り他のクラスから見えてしまいます。

実行例:Animal → Dog の継承

// Java 21 - 継承の動作確認
public class Main {
 public static void main(String[] args) {
 Dog dog = new Dog("Shiba");
 dog.eat(); // Animal から継承
 dog.bark(); // Dog 独自

 Bird bird = new Bird("Sparrow");
 bird.eat(); // Bird でオーバーライド
 bird.fly(); // Bird 独自
 }
}

実行結果:

Shiba is eating.
Shiba is barking: Woof!
Sparrow is pecking seeds.
Sparrow is flying.

Birdeat() はオーバーライドされているため、Animal の実装ではなく Bird の実装が呼ばれます。

super でスーパークラスのメソッドを呼び出す

オーバーライドしたメソッドの中で、スーパークラスの元の実装を呼び出すこともできます。

// Java 21 - super でスーパークラスのメソッドを再利用
public class Bird extends Animal {
 public Bird(String name) {
 super(name);
 }

 @Override
 public void eat() {
 super.eat(); // Animal の eat() を呼び出す
 System.out.println(" (pecking seeds)");
 }
}

実行結果:

Sparrow is eating.
 (pecking seeds)

super.eat() で親の処理を実行してから、追加のメッセージを出力しています。

ヒント: super はフィールドアクセスにも使えます。super.name でスーパークラスの name を明示的に参照できます(ただし同名フィールドを子で再定義するのは混乱の元なので避けましょう)。

プログラミングのベストプラクティス

やるべきこと理由
@Override を必ず付けるタイポや引数ミスをコンパイル時に検出
protected を適切に使うサブクラスにのみ公開したいフィールド・メソッド
継承は「is-a 関係」のときだけDog is an Animal → 自然。Car is an Engine → 不自然(コンポジションを使う)
深い継承階層を避ける3階層以上になると理解困難。設計を見直す

注意: 継承は強力ですが、使いすぎると密結合になります。「コードの再利用」だけが目的なら、後に学ぶ コンポジション(has-a 関係)や インターフェース の方が適切なケースも多いです

次のステップ

次回以降では以下のトピックを扱います。

  • ポリモーフィズム: Animal animal = new Dog(); のようなアップキャスト
  • abstract クラス: 抽象メソッドを持つクラス
  • インターフェース: 複数実装可能な型の契約

Java入門 #22 - ポリモーフィズムとアップキャスト(今後追加予定)

まとめ

この記事では、手順を追って動かしながら重要な確認ポイントを押さえることが大切です。まずは学習用の最小構成で動作確認し、本番利用する前にセキュリティ、権限、エラー処理、運用手順を見直してください。

参考リソース

← 一覧に戻る
PR
PR
PR
PR