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
に近い合図。(実際には名前が変換され、外部からアクセスしにくくなります)
まとめ
項目 | Java | Python |
継承の数 | 単一継承のみ | 多重継承が可能 |
多重継承の代替 | インターフェースをimplements する | (不要) |
継承の構文 | class Child extends Parent | class Child(Parent): |
親コンストラクタ | super(args) | super().__init__(args) |
アクセス制御 | public , private などで厳密に制限 | _ や __ を使う慣習(紳士協定) |
Javaは安全性を重視して厳格なルールを設けているのに対し、Pythonは「私たちは皆、大人だ」という考えのもと、プログラマーの裁量に任せる部分が多いのが特徴です。どちらが良いというわけではなく、設計思想の違いとして理解することが大切ですよ。