Javaを学習していると、「クラスの継承は1つしかできない(単一継承)」というルールに必ず直面します。
C++やPythonなどの言語では複数のクラスを継承する「多重継承」が可能ですが、なぜJavaでは禁止されているのでしょうか。
「インターフェースなら複数実装できると聞いたけれど、何が違うの?」
このような疑問を持つ方のために、この記事ではJavaがクラスの多重継承を禁止している理由である「ダイヤモンド問題」の解説から、インターフェースを使った多重継承(多重実装)の具体的なコーディング方法、そしてJava 8以降で導入された「デフォルトメソッド」における注意点までを徹底的に解説します。
Javaでクラスの多重継承が禁止されている理由
Javaの設計思想において、クラスの多重継承(extends A, B のような記述)は明確に禁止されています。
その最大の理由は、言語仕様をシンプルに保ち、「ダイヤモンド問題」と呼ばれる致命的な衝突を避けるためです。
メソッドの衝突「ダイヤモンド問題」とは
もしJavaでクラスの多重継承が許可されていたとしたら、どのような問題が起きるのでしょうか。
例えば、以下のような継承関係を想像してみてください。
- クラスA(親):「挨拶する」メソッドを持っている。
- クラスB(Aの子):「挨拶する」を「こんにちは」とオーバーライド。
- クラスC(Aの子):「挨拶する」を「こんばんは」とオーバーライド。
- クラスD(BとCの両方を継承した子)
このとき、クラスDのインスタンスで「挨拶する」メソッドを呼び出した場合、「Bの『こんにちは』」と「Cの『こんばんは』」のどちらを実行すれば良いのか、コンピュータは判断できなくなってしまいます。
継承図を描くと菱形(ダイヤモンド)の形状になることから、これを「ダイヤモンド問題」と呼びます。
Javaはこの複雑さを回避するために、クラスの継承を1つに限定しています。
インターフェースを使った多重継承(多重実装)の方法
クラスの多重継承はできませんが、Javaでは「インターフェース」を複数実装(implements)することは許可されています。
インターフェースは「仕様(メソッドの型)」のみを定義し、実体(中身のコード)を持たないことが基本だったため、メソッドが衝突しても問題にならなかったからです(どちらの実装を使うか悩む必要がなく、実装するクラス側で定義するため)。
複数のインターフェースを実装するサンプルコード
それでは、実際に2つのインターフェースを1つのクラスに実装する例を見てみましょう。
// 1つ目のインターフェース
interface Camera {
void takePicture();
}
// 2つ目のインターフェース
interface MusicPlayer {
void playMusic();
}
// 2つのインターフェースを実装したスマートフォンクラス
// カンマ区切りで複数のインターフェースを指定できる
class SmartPhone implements Camera, MusicPlayer {
@Override
public void takePicture() {
System.out.println("写真を撮影しました。");
}
@Override
public void playMusic() {
System.out.println("音楽を再生します。");
}
}
public class Main {
public static void main(String[] args) {
SmartPhone myPhone = new SmartPhone();
myPhone.takePicture();
myPhone.playMusic();
}
}
実行結果
写真を撮影しました。
音楽を再生します。
class SmartPhone implements Camera, MusicPlayer のように、implements キーワードの後ろにカンマ区切りでインターフェースを並べることで、複数の機能を持ったクラスを定義できます。
SmartPhone クラスは、Camera としての機能(takePicture)と MusicPlayer としての機能(playMusic)の両方を強制的に実装させられます。
これにより、擬似的な多重継承のような振る舞いを安全に実現しています。
Java 8以降のデフォルトメソッドと競合の解決
Java 8からはインターフェースに「デフォルトメソッド(default method)」という機能が追加されました。
これにより、インターフェース自体にメソッドの実装(中身)を持てるようになりましたが、同時に「ダイヤモンド問題」に似たメソッドの競合が発生する可能性も生まれました。
デフォルトメソッドが競合した場合のルール
同じ名前・同じ引数のデフォルトメソッドを持つ2つのインターフェースを実装した場合、コンパイルエラーになります。
この場合、実装するクラス側で「どちらのメソッドを使うか」を明示的にオーバーライドして指定する必要があります。
interface InterfaceA {
default void hello() {
System.out.println("InterfaceAのこんにちは");
}
}
interface InterfaceB {
default void hello() {
System.out.println("InterfaceBのこんにちは");
}
}
// 両方に hello() があるため、そのままだとコンパイルエラーになる
class MyClass implements InterfaceA, InterfaceB {
@Override
public void hello() {
// どちらを使うか明示的に記述する
// InterfaceA.super.メソッド名() で指定可能
InterfaceA.super.hello();
// もちろん、独自の処理を書いてもOK
System.out.println("MyClassで解決しました");
}
}
public class DefaultMethodMain {
public static void main(String[] args) {
MyClass obj = new MyClass();
obj.hello();
}
}
実行結果
InterfaceAのこんにちは
MyClassで解決しました
InterfaceA と InterfaceB の両方に default void hello() が定義されています。
MyClass がこれらを同時に実装しようとすると、コンパイラはどちらの hello を使えばよいかわからないためエラーを出します。
そこで、MyClass 内で hello メソッドをオーバーライドし、InterfaceA.super.hello() のように記述して「Aの実装を使う」と明示するか、あるいは全く新しい処理を記述することで解決します。
クラス継承とインターフェース実装の優先順位
もし、親クラスとインターフェースの両方に同じメソッドがあった場合はどうなるのでしょうか?
Javaには「クラス優先の法則(Class Wins)」というルールがあります。
クラスの実装が常に勝つ
class SuperClass {
public void method() {
System.out.println("親クラスのメソッド");
}
}
interface MyInterface {
default void method() {
System.out.println("インターフェースのデフォルトメソッド");
}
}
// 親クラスを継承し、インターフェースも実装
class ChildClass extends SuperClass implements MyInterface {
// 何も書かなくてもエラーにならない
}
public class ClassWinsMain {
public static void main(String[] args) {
ChildClass obj = new ChildClass();
obj.method();
}
}
実行結果
親クラスのメソッド
SuperClass と MyInterface の両方に method() がありますが、この場合はコンパイルエラーにはならず、自動的に親クラス(SuperClass)のメソッドが優先して使用されます。
クラスの継承関係による振る舞いの保証を、インターフェースの拡張(デフォルトメソッド)よりも重要視しているためです。
このルールのおかげで、既存のクラス設計を壊さずにインターフェースを進化させることが可能になっています。
Javaのスキルを活かして年収を上げる方法
以上、Javaでクラスの多重継承が禁止されている理由や、多重継承を実現する方法などについて解説してきました。
なお、Javaのスキルがある場合には、「転職して年収をアップさせる」「副業で稼ぐ」といった方法を検討するのがおすすめです。
Javaエンジニアの需要は非常に高いため、転職によって数十万円の年収アップはザラで、100万円以上年収が上がることも珍しくありません。
なお、転職によって年収を上げたい場合は、エンジニア専門の転職エージェントサービスを利用するのが最適です。
併せて、副業案件を獲得できるエージェントにも登録しておくと、空いている時間を活かして稼げるようなJavaの案件を探しやすくなります。
転職エージェントも副業エージェントも、登録・利用は完全無料なので、どんな求人や副業案件があるのか気になる方は、気軽に利用してみるとよいでしょう。


