Javaは安全性を重視して厳格なルールを、Pythonはプログラマーの裁量に任せている 継承を例に解説

こんにちは。ゆうせいです。

JavaとPythonの継承は、基本的な考え方は同じですが、仕組みや書き方にいくつか重要な違いがあります。特に多重継承の扱いが大きく異なります。


継承の基本コンセプト

継承は、オブジェクト指向プログラミングの基本的な考え方で、すでにあるクラス(親クラスまたはスーパークラス)の性質(属性やメソッド)を引き継いで、新しいクラス(子クラスまたはサブクラス)を作成する仕組みです。

これにより、コードの再利用性が高まり、効率的な開発が可能になります。例えば、「動物」クラスを親として、「犬」クラスや「猫」クラスを作ると、「犬」や「猫」は動物が持つ「食べる」「寝る」といった基本的な機能をそのまま受け継ぐことができます。これはどちらの言語でも共通です。


構文とコンストラクタ呼び出しの違い

まずは、コードの書き方の違いを見てみましょう。「動物」クラスと、それを継承した「犬」クラスを例にします。

Javaの例

Javaではextendsキーワードで継承を示し、親のコンストラクタはsuper()で呼び出します。

// 親クラス
class Animal {
    String name;

    // 親クラスのコンストラクタ
    public Animal(String name) {
        this.name = name;
        System.out.println("Animalのコンストラクタが呼ばれました");
    }
}

// 子クラス
class Dog extends Animal {
    // 子クラスのコンストラクタ
    public Dog(String name) {
        // 必ず最初に親のコンストラクタを呼ぶ
        super(name);
        System.out.println("Dogのコンストラクタが呼ばれました");
    }

    public void bark() {
        // 親クラスのname属性を使える
        System.out.println(this.name + ": ワンワン!");
    }
}

// 実行
Dog pochi = new Dog("ポチ");
pochi.bark();

Pythonの例

Pythonではクラス名の後ろの( )に親クラスを書き、親のコンストラクタはsuper().__init__()で呼び出します。

# 親クラス
class Animal:
    # 親クラスのコンストラクタ
    def __init__(self, name):
        self.name = name
        print("Animalのコンストラクタが呼ばれました")

# 子クラス
class Dog(Animal):
    # 子クラスのコンストラクタ
    def __init__(self, name):
        # 親のコンストラクタを呼ぶ
        super().__init__(name)
        print("Dogのコンストラクタが呼ばれました")

    def bark(self):
        # 親クラスのname属性を使える
        print(f"{self.name}: ワンワン!")

# 実行
pochi = Dog("ポチ")
pochi.bark()

最大の違い:多重継承の可否

これがJavaとPythonの最も決定的な違いです。

Java:単一継承 + インターフェース

Javaでは、一つのクラスが継承できる親クラスは一つだけです(これを単一継承と呼びます)。複数のクラスをextendsで指定することはできません。

これは、複数の親が同じ名前のメソッドを持っていた場合に、どちらを呼べばいいか分からなくなる「ダイヤモンド問題」という複雑な問題を避けるためです。

その代わり、Javaにはインターフェースという仕組みがあります。インターフェースは「実装すべきメソッドのリスト」を定義した契約書のようなもので、クラスは複数のインターフェースをimplements(実装)できます。これにより、多重継承のように複数の性質をクラスに持たせることができます。

例えるなら、Javaのクラスは「生みの親は一人だけ(単一継承)だけど、ピアノの先生やサッカーのコーチなど、複数の師匠から技術を学ぶことができる(インターフェースの実装)」というイメージです。

interface Flyable { void fly(); }
interface Swimmable { void swim(); }

// DuckクラスはAnimalを継承しつつ、2つのインターフェースを実装
class Duck extends Animal implements Flyable, Swimmable {
    // ... fly()とswim()を実装する必要がある
}

Python:多重継承が可能

一方、Pythonは複数のクラスを直接継承する多重継承をサポートしています。

class Father:
    def work(self):
        print("父:会社で働く")

class Mother:
    def cook(self):
        print("母:料理をする")

# 2つのクラスを継承
class Child(Father, Mother):
    pass

# Childは両方の親のメソッドを使える
c = Child()
c.work() # => 父:会社で働く
c.cook() # => 母:料理をする



Pythonはダイヤモンド問題に対して、メソッド解決順序(MRO)という明確なルールを持っているため、多重継承が許されています。しかし、むやみに使うとクラスの関係が複雑になりすぎるため、慎重に使うべき機能とされています。


アクセス修飾子の違い

メソッドや属性をどこから呼び出せるかを制御する「アクセス修飾子」の考え方も異なります。

  • Java: public, protected, privateといったキーワードで厳密にアクセスを制限します。これはコンパイラによって強制されます。
  • Python: このような厳密なアクセス制限はありません。プログラマー間の「紳士協定」として、名前の先頭にアンダースコアを付けることで表現します。
    • _variable: 「外部から直接触らないでね」というprotectedに近い合図。
    • __variable: 「クラスの内部だけで使うよ」というprivateに近い合図。(実際には名前が変換され、外部からアクセスしにくくなります)

まとめ

項目JavaPython
継承の数単一継承のみ多重継承が可能
多重継承の代替インターフェースimplementsする(不要)
継承の構文class Child extends Parentclass Child(Parent):
親コンストラクタsuper(args)super().__init__(args)
アクセス制御public, privateなどで厳密に制限___ を使う慣習(紳士協定)

Javaは安全性を重視して厳格なルールを設けているのに対し、Pythonは「私たちは皆、大人だ」という考えのもと、プログラマーの裁量に任せる部分が多いのが特徴です。どちらが良いというわけではなく、設計思想の違いとして理解することが大切ですよ。

セイ・コンサルティング・グループの新人エンジニア研修のメニューへのリンク

投稿者プロフィール

山崎講師
山崎講師代表取締役
セイ・コンサルティング・グループ株式会社代表取締役。
岐阜県出身。
2000年創業、2004年会社設立。
IT企業向け人材育成研修歴業界歴20年以上。
すべての無駄を省いた費用対効果の高い「筋肉質」な研修を提供します!
この記事に間違い等ありましたらぜひお知らせください。