本文へスキップ
T2R tech2rich.com
プログラミング 📚 Java入門 第10回 #Java #入門 #プログラミング初心者 #継承 #インターフェース #オブジェクト指向

【Java入門 第10回】継承・インターフェースを完全マスター|オブジェクト指向の核心

Javaのオブジェクト指向の真打ち「継承」と「インターフェース」を完全初心者向けに徹底解説。extends と implements の違い、ポリモーフィズム、@Override までしっかり押さえます。

📅 公開: 2026.05.23 🔄 更新: 2026.05.23 ⏱ 読了 約7分 ✍ 管理人

第7回 でクラスとオブジェクトを学びました。今回はオブジェクト指向の真打ちである 「継承(けいしょう)」「インターフェース」 を学びます。

「同じようなクラスを何個も書くのが面倒…」── 継承を使えば、既存のクラスを土台にして新しいクラスを作ることができ、コードの重複を一気に減らせます

先輩

この記事のゴール

「継承(extends)とは?」「インターフェース(implements)とは?」「@Override の意味」「ポリモーフィズムって何?」が理解できることです。難しそうな言葉ですが、1つずつ噛み砕いていきます!

継承とは?(ざっくり 30 秒で)

継承 とは、既存のクラス(親)を そのまま受け継いで、新しいクラス(子)を作る仕組みです。

💡 イメージ: 親クラスを 「基本セット」 として、子クラスで 「カスタマイズ」 していく感じ。

たとえば「動物」クラスを作り、それを継承して「犬」「猫」「鳥」を作れば、共通の特徴(名前、年齢、鳴く)は親クラスに 1 度だけ書けば OK。子クラスは 「鳥は飛べる」などの独自の特徴だけ追加すればよくなります。

継承の基本: extends

親クラス(基本セット)

// Animal.java(親クラス)
public class Animal {
    String name;       // 名前
    int age;           // 年齢

    // コンストラクタ
    public Animal(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // 全ての動物が持つメソッド
    public void introduce() {
        System.out.println(name + "(" + age + "歳)です。");
    }
}

子クラス(extends で継承)

// Dog.java(子クラス)
//   ↓ extends で親クラス Animal を継承
public class Dog extends Animal {

    // 子クラスのコンストラクタ
    public Dog(String name, int age) {
        super(name, age);   // ← 親のコンストラクタを呼ぶ(必須)
    }

    // 犬だけの独自メソッド(親にはない)
    public void bark() {
        System.out.println(name + "「ワンワン!」");
    }
}

重要ポイント:

使ってみる

public class Main {
    public static void main(String[] args) {
        Dog pochi = new Dog("ポチ", 3);
        pochi.introduce();   // ← 親クラスのメソッドが使える!→ ポチ(3歳)です。
        pochi.bark();         // ← 子クラスのメソッド → ポチ「ワンワン!」
    }
}

1 行も書いていない introduce() が使えるのが、継承の強みです。

メソッドのオーバーライド: @Override

「親のメソッドの中身を 子クラスで書き換えたい」── そんなときは オーバーライド(上書き) します。

public class Cat extends Animal {

    public Cat(String name, int age) {
        super(name, age);
    }

    // 親の introduce() を上書き(書き換え)
    @Override                                 // ← この目印を付けると安全
    public void introduce() {
        System.out.println(name + "は猫。気まぐれです。");
    }
}
Cat tama = new Cat("タマ", 2);
tama.introduce();   // → タマは猫。気まぐれです。(親の introduce() ではなく子が呼ばれる)

💡 @Override の意味: 「これは親のメソッドを上書きするつもりだよ」というコンパイラへの宣言。スペルミスなどで上書きできていないと自動でエラーになるので、必ず付ける習慣にしましょう。

インターフェースとは?

インターフェース は、「このクラスはこういう機能を持つ」という約束を定義する仕組みです。

💡 イメージ: クラスが 「設計図」 なら、インターフェースは 「契約書」。 「電話できる」「メッセージ送れる」と書かれた契約書(インターフェース)に、スマホ・ガラケー・固定電話などの 異なるクラス がサインする感じです。

インターフェースの宣言

// Flyable.java(インターフェース)
//   ↓ class ではなく interface と書く
public interface Flyable {
    // メソッドの「約束」だけを書く(中身は書かない)
    void fly();
}

インターフェースを実装するクラス

// Bird.java
//   ↓ extends ではなく implements(実装する)
public class Bird extends Animal implements Flyable {

    public Bird(String name, int age) {
        super(name, age);
    }

    // インターフェースで約束した fly() の中身を書く(必須)
    @Override
    public void fly() {
        System.out.println(name + "は空を飛ぶ!");
    }
}

ポイント:

継承とインターフェースの違い

観点継承(extends)インターフェース(implements)
何を継承する?実体(フィールド + メソッド)」約束(メソッドの宣言だけ)」
多重継承❌ 1 つの親しか継承できない複数実装できる
キーワードextendsimplements
使う場面「is-a」関係(犬は動物だ)「can-do」関係(犬は走れる)

複数のインターフェースを同時実装

public class Duck extends Animal implements Flyable, Swimmable {
    // Flyable と Swimmable を両方実装する場合、両方のメソッドを書く
    @Override
    public void fly() {
        System.out.println(name + "は飛ぶ!");
    }

    @Override
    public void swim() {
        System.out.println(name + "は泳ぐ!");
    }
}

ポリモーフィズム(多態性)

ポリモーフィズム(多態性) ── 名前は長いですが、要は 「親の型で、子のオブジェクトを扱える」 ということです。

// 親の型 (Animal) で、子のオブジェクト (Dog, Cat, Bird) を扱える!
Animal[] animals = {
    new Dog("ポチ", 3),
    new Cat("タマ", 2),
    new Bird("ピーコ", 1)
};

// 同じ for 文ですべての動物を introduce
for (Animal a : animals) {
    a.introduce();
    // → ポチ(3歳)です。
    // → タマは猫。気まぐれです。  ← Cat の introduce が呼ばれる(オーバーライド済み)
    // → ピーコ(1歳)です。
}

何が嬉しいか?: 新しい動物クラス(Rabbit など)を追加しても、main の for 文は一切変えなくていい。これがオブジェクト指向の真骨頂です。

ポイント

編集部からのポイント

ポリモーフィズムは初心者には難しく感じますが、「親の型を箱として使うと、中身を入れ替えても外側のコードは変わらない」と覚えれば OK。フレームワーク(Spring など)はこの仕組みでできています。

ハマりがちな落とし穴

落とし穴①: super() を忘れる

public Dog(String name, int age) {
    // super() を書かないと、コンパイラが自動で super() を入れる
    // でも親に引数なしコンストラクタがないとエラー!
}

対処: 子クラスのコンストラクタの 最初の行super(...) を必ず書く習慣を。

落とし穴②: private なフィールドにアクセスできない

public class Animal {
    private String name;  // private は外から見えない
}

public class Dog extends Animal {
    public void show() {
        System.out.println(name);  // ❌ コンパイルエラー
    }
}

対処: 親で protected(継承先からは見える)にするか、ゲッターメソッド を作って呼ぶ。

落とし穴③: 親と子で同じフィールド名を持つ

public class Parent { int value = 10; }
public class Child extends Parent { int value = 20; }

対処: 基本的に避けましょう。混乱の元です。

練習問題

動物(Animal)を継承した (Dog)と (Cat)」を作り、それぞれに makeSound() メソッドをオーバーライドで実装してください。

解答例

// Animal.java
public class Animal {
    String name;

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

    public void makeSound() {
        System.out.println(name + "が鳴いた");
    }
}

// Dog.java
public class Dog extends Animal {
    public Dog(String name) {
        super(name);
    }

    @Override
    public void makeSound() {
        System.out.println(name + "「ワンワン!」");
    }
}

// Cat.java
public class Cat extends Animal {
    public Cat(String name) {
        super(name);
    }

    @Override
    public void makeSound() {
        System.out.println(name + "「ニャー」");
    }
}

// Main.java
public class Main {
    public static void main(String[] args) {
        // Animal[] に犬と猫を入れる(ポリモーフィズム!)
        Animal[] animals = { new Dog("ポチ"), new Cat("タマ") };

        for (Animal a : animals) {
            a.makeSound();  // 中身に応じて Dog or Cat の makeSound が呼ばれる
        }
        // → ポチ「ワンワン!」
        // → タマ「ニャー」
    }
}

まとめ

第 10 回では、以下を学びました。

次回は 「ファイル入出力」 を学びます。File / Scanner を使って、ファイルから読み込んだり書き込んだりする方法を解説します。お楽しみに!

関連の技術記事