1. 概要

このクイックチュートリアルでは、 java.lang.IllegalAccessErrorについて説明します。

スローされるタイミングの例と、それを回避する方法を検討します。

2. IllegalAccessErrorの概要

アプリケーションがフィールドにアクセスしようとしたり、アクセスできないメソッドを呼び出したりしようとすると、IllegalAccessErrorがスローされます。

コンパイラはそのような不正な呼び出しをキャッチしますが、実行時にIllegalAccessErrorにぶつかる可能性があります。

まず、 IllegalAccessError:のクラス階層を観察してみましょう。

java.lang.Object
  |_java.lang.Throwable
    |_java.lang.Error
      |_java.lang.LinkageError
        |_java.lang.IncompatibleClassChangeError
          |_java.lang.IllegalAccessError

その親クラスは IncompatibleClassChangeError。 したがって、このエラーの原因は、アプリケーションの1つ以上のクラス定義の互換性のない変更です。

簡単に言えば、実行時のクラスのバージョンは、コンパイルされたものとは異なります。

3. このエラーはどのように発生しますか?

簡単なプログラムでこれを理解しましょう:

public class Class1 {
    public void bar() {
        System.out.println("SUCCESS");
    }
}

public class Class2 {
    public void foo() {
        Class1 c1 = new Class1();
        c1.bar();
    }
}

実行時に、上記のコードはメソッドを呼び出しますバー()クラス1。 ここまでは順調ですね。

それでは、 bar()のアクセス修飾子を private に更新し、個別にコンパイルしてみましょう。

次に、 Class1の以前の定義(。クラスファイルを新しくコンパイルされたバージョンに置き換えて、プログラムを再実行します。

java.lang.IllegalAccessError: 
  class Class2 tried to access private method Class1.bar()

上記の例外は自明です。 方法バー() 今でしょプライベートクラス1。 明らかに、アクセスすることは違法です。

4. IllegalAccessErrorの動作

4.1. ライブラリの更新

コンパイル時にライブラリを使用するアプリケーションについて考えてみます。同じことが実行時にクラスパスでも利用できます。

ライブラリの所有者は、公開されているメソッドをプライベートに更新して再構築しますが、この変更の他の関係者を更新するのを忘れています。

さらに、実行中にアプリケーションがこのメソッドを呼び出すと(パブリックアクセスを想定)、IllegalAccessError。が発生します。

4.2. インターフェイスのデフォルトメソッド

インターフェイスでのデフォルトメソッドの誤用は、このエラーのもう1つの原因です。

次のインターフェイスとクラスの定義を検討してください。

interface Baeldung {
    public default void foobar() {
        System.out.println("This is a default method.");
    }
}

class Super {
    private void foobar() {
        System.out.println("Super class method foobar");
    }
}

また、 Super を拡張して、 Baeldung:を実装しましょう。

class MySubClass extends Super implements Baeldung {}

最後に、 MySubClass:をインスタンス化して、 foobar()を呼び出しましょう。

new MySubClass().foobar();

方法 foobar() でプライベートです素晴らしいデフォルト Baeldung。 したがって、 次の階層でアクセスできます MySubClass。

したがって、コンパイラは文句を言いませんが、実行時にエラーが発生します。

java.lang.IllegalAccessError:
  class IllegalAccessErrorExample tried to access private method 'void Super.foobar()'

実行中、スーパークラスメソッド宣言は常にインターフェイスのデフォルトメソッドよりも優先されます。

技術的には、Superfoobarが呼び出されるべきでしたが、プライベートです。 間違いなく、IllegalAccessErrorがスローされます。

5. それを避ける方法は?

正確には、 IllegalAccessError に遭遇した場合、アクセス修飾子に関するクラス定義の変更を主に探す必要があります。

次に、プライベートアクセス修飾子でオーバーライドされたインターフェイスのデフォルトメソッドを検証する必要があります。

クラスレベルのメソッドをパブリックにすることでうまくいきます。

6. 結論

結論として、コンパイラは不正なメソッド呼び出しのほとんどを解決します。 それでもIllegalAccesErrorに遭遇する場合は、クラス定義の変更を調べる必要があります。

例のソースコードは、GitHubから入手できます。