web-dev-qa-db-ja.com

プライベートメソッドと競合しているときにインターフェイスのデフォルトメソッドを呼び出す

以下のクラス階層を検討してください。

_class ClassA {
    private void hello() {
        System.out.println("Hello from A");
    }
}

interface Myinterface {
    default void hello() {
        System.out.println("Hello from Interface");
    }
}

class ClassB extends ClassA implements Myinterface {

}

public class Test {
    public static void main(String[] args) {
        ClassB b = new ClassB();
        b.hello();
    }
}
_

プログラムを実行すると、次のエラーが発生します。

_Exception in thread "main" Java.lang.IllegalAccessError: tried to access method com.testing.ClassA.hello()V from class com.testing.Test
at com.testing.Test.main(Test.Java:23)
_
  1. これは、ClassA.helloをプライベートとしてマークしたためです。
  2. ClassA.helloを保護済みとしてマークするか、可視性修飾子を削除する(つまり、デフォルトのスコープにする)と、コンパイラエラーが次のように表示されます:The inherited method ClassA.hello() cannot hide the public abstract method in Myinterface

ただし、上記の例外スタックトレースに従って、ランタイムIllegalAccessErrorが発生します。

コンパイル時にこれが検出されない理由を理解できませんでした。手がかりはありますか?

39

更新:それは本当に bug

クラスまたはスーパークラスのメソッド宣言は、常にデフォルトのメソッドよりも優先されます。

Myinterfacedefault hello(...)メソッドを使用すると、エラーなしで書き込むことができます。

_ClassB b = new ClassB();
b.hello();
_

実行時まで、実行時にClassAからのhello(...)メソッドが最も優先されます(ただし、メソッドはプライベートです)。したがって、IllegalAccessErrorが発生します。

インターフェースからデフォルトのhello(...)メソッドを削除すると、同じ不正アクセスエラーが発生しますが、今はコンパイル時です。

29