継承

継承はOOPのコア機能の一つで、コード再利用を可能にします。

継承とは

継承により、サブクラスは親クラスから属性とメソッドを継承し、コード再利用を可能にします。

継承の利点

利点 説明
コード再利用 親クラスのコードを再記述する必要がない
拡張性 サブクラスが独自の属性とメソッドを追加可能
ポリモーフィズムの基盤 継承はポリモーフィズムの前提条件

extendsキーワード

構文

JAVA
public class 子クラス extends 親クラス {
    // 子クラス固有の属性とメソッド
}

例:継承

JAVA
// 親クラス
public class Animal {
    String name;
    int age;
    
    public void eat() {
        System.out.println(name + "は食べている");
    }
    
    public void sleep() {
        System.out.println(name + "は寝ている");
    }
}

// 子クラス
public class Dog extends Animal {
    String breed;
    
    public void bark() {
        System.out.println(name + "は吠えている");
    }
}

public class Cat extends Animal {
    String color;
    
    public void meow() {
        System.out.println(name + "は鳴いている");
    }
}

public class InheritanceDemo {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.name = "Buddy";
        dog.age = 3;
        dog.breed = "Golden Retriever";
        
        dog.eat();    // Buddyは食べている(Animalから継承)
        dog.sleep();  // Buddyは寝ている(Animalから継承)
        dog.bark();   // Buddyは吠えている(Dog独自のメソッド)
        
        Cat cat = new Cat();
        cat.name = "Whiskers";
        cat.age = 2;
        cat.color = "White";
        
        cat.eat();    // Whiskersは食べている
        cat.meow();   // Whiskersは鳴いている
    }
}
▶ 試してみよう

superキーワード

superは親クラスへの参照です。

用途1:親コンストラクタの呼び出し

JAVA
public class Animal {
    String name;
    int age;
    
    public Animal(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

public class Dog extends Animal {
    String breed;
    
    public Dog(String name, int age, String breed) {
        super(name, age);  // 親コンストラクタを呼び出し
        this.breed = breed;
    }
}

用途2:親メソッドの呼び出し

JAVA
public class Animal {
    public void eat() {
        System.out.println("動物が食べている");
    }
}

public class Dog extends Animal {
    @Override
    public void void eat() {
        super.eat();  // 親のeatを呼び出し
        System.out.println("犬は骨をかじっている");
    }
}

例:superの使用

JAVA
public class Person {
    protected String name;
    protected int age;
    
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    public void showInfo() {
        System.out.println("名前: " + name + ", 年齢: " + age);
    }
}

public class Student extends Person {
    private double score;
    
    public Student(String name, int age, double score) {
        super(name, age);  // 親コンストラクタを呼び出し
        this.score = score;
    }
    
    @Override
    public void showInfo() {
        super.showInfo();  // 親のshowInfoを呼び出し
        System.out.println("スコア: " + score);
    }
}

public class SuperDemo {
    public static void main(String[] args) {
        Student stu = new Student("Alice", 20, 95.5);
        stu.showInfo();
        // 名前: Alice, 年齢: 20
        // スコア: 95.5
    }
}
▶ 試してみよう

メソッドオーバーライド

サブクラスは親クラスのメソッドをオーバーライドして、異なる動作を実装できます。

オーバーライドルール

ルール 説明
同じメソッド名 必須
同じパラメータリスト 必須
同じ戻り値の型 または親の戻り値の型のサブクラス
アクセスをより制限的にできない より寛大にすることは可能

@Overrideアノテーション

JAVA
public class Dog extends Animal {
    @Override
    public void eat() {
        System.out.println("犬は骨をかじっている");
    }
}
💡 推奨: メソッドをオーバーライドするときは常に@Overrideアノテーションを追加してください。コンパイラがオーバーライドが正しいことを確認します。

Objectクラス

すべてのクラスは直接的または間接的にObjectクラスから継承します。

一般的なObjectメソッド

メソッド 説明
toString() オブジェクトの文字列表現を返す
equals() オブジェクトの等価性を比較
hashCode() オブジェクトのハッシュコードを返す
getClass() オブジェクトのクラス情報を返す

toString()のオーバーライド

JAVA
public class Student {
    private String name;
    private int age;
    
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    @Override
    public String toString() {
        return "Student{name='" + name + "', age=" + age + "}";
    }
    
    public static void main(String[] args) {
        Student stu = new Student("Alice", 20);
        System.out.println(stu);  // 自動的にtoString()を呼び出し
        // 出力: Student{name='Alice', age=20}
    }
}

equals()のオーバーライド

JAVA
public class Student {
    private String name;
    private int age;
    
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (obj == null || getClass() != obj.getClass()) return false;
        Student other = (Student) obj;
        return age == other.age && name.equals(other.name);
    }
    
    @Override
    public int hashCode() {
        return name.hashCode() * 31 + age;
    }
    
    public static void main(String[] args) {
        Student s1 = new Student("Alice", 20);
        Student s2 = new Student("Alice", 20);
        
        System.out.println(s1 == s2);      // false(異なるオブジェクト)
        System.out.println(s1.equals(s2)); // true(同じ内容)
    }
}

instanceof

instanceof演算子は、オブジェクトが特定のクラスのインスタンスかどうかをチェックします。

JAVA
public class InstanceofDemo {
    public static void main(String[] args) {
        Dog dog = new Dog();
        
        System.out.println(dog instanceof Dog);    // true
        System.out.println(dog instanceof Animal); // true
        System.out.println(dog instanceof Object); // true
    }
}

継承の注意事項

注意事項 説明
単一継承 Javaは単一継承のみサポート
privateは継承できない privateメンバーは継承できない
コンストラクタは継承できない コンストラクタは継承できない
Objectはルートクラス すべてのクラスはObjectから継承

❓ よくある質問

Q Javaはなぜ多重継承をサポートしないのですか?
A ダイヤモンド問題(複数の親が同じメソッドを持つ場合のあいまいさ)を避けるためです。Javaはインターフェースで同様の機能を提供します。
Q いつ継承を使用すべきですか?
A 2つのクラスが「is-a」関係を持つ場合、例えばDog is a Animal。
Q 継承とコンポジションのどちらを選ぶべきですか?
A コンポジション(has-a関係)を優先してください。継承は結合度を高めます。

📖 まとめ

📝 演習

  1. Shape階層: Shape親クラスとCircle、Rectangleサブクラスを定義し、面積を計算
  2. Employee階層: Employee親クラスとManager、Developerサブクラスを定義
  3. toString/equals: StudentクラスのtoStringとequalsメソッドをオーバーライド

次のレッスン

次のレッスンでは、ポリモーフィズムと抽象を学びます — OOPのコア機能。

100%