【Java進化史 第22回 後編】defaultメソッドの注意点 〜 どこまで“クラス化”したのか 〜
前回、インターフェースに実装を書くという事実に、 正直な違和感を覚えた。
今回は、少し冷静に整理してみる。
defaultメソッドは、 どこまで許されているのか。
■ defaultメソッドは何ができるのか
まずは単純な例から。
public interface Sample {
int VALUE = 10; // 定数は持てる(public static final)
int calc(int x);
default int doubleCalc(int x) {
return calc(x) * VALUE;
}
}
ここで注目すべき点は2つある。
- インターフェースは定数(public static final)しか持てない
- defaultメソッドは他の抽象メソッドを呼び出せる
つまり、 defaultメソッドは「振る舞いの共通化」はできる。
しかし、 状態は持てない。
インスタンスフィールドは宣言できない。 コンストラクタもない。
ここは、クラスとは決定的に違う。
defaultメソッドは、 クラスの代わりではない。
あくまで、 契約の延長線上にある“補助的な実装”だ。
■ 多重継承はどうなるのか
では、インターフェースが複数あったらどうなるのか。
interface A {
default void hello() {
System.out.println("A");
}
}
interface B {
default void hello() {
System.out.println("B");
}
}
class C implements A, B {
}
これはコンパイルエラーになる。
どちらのhelloを使うのか、 曖昧だからだ。
Javaは、この曖昧さを許さない。
必ず、実装クラス側で明示的に解決する必要がある。
class C implements A, B {
@Override
public void hello() {
A.super.hello();
}
}
このように、 どのインターフェースの実装を使うかを 明示的に指定する。
「なんとなく動く」は許されない。
■ 原則は壊れていない
インターフェースは、今でも状態を持たない。
完全なクラスになったわけではない。
defaultメソッドは、 無制限の自由ではない。
制御された拡張である。
だからこそ、 長年守られてきた設計思想は、 完全に崩れたわけではない。
むしろ、 後方互換性を守りながら進化するための、 現実的な選択だったと言える。
違和感はある。
だが、無秩序ではない。
そこが、Javaらしさなのかもしれない。
0 件のコメント:
コメントを投稿