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

它的父类是 IncompleteClassChangeError。 因此,此错误的原因是应用程序中一个或多个类定义的不兼容更改。

简而言之, 运行时类的版本与编译时所针对的版本不同。

3. 如何出现此错误?

让我们通过一个简单的程序来理解这一点:

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

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

在运行时,上面的代码调用 Class1 中的方法 bar() 。到目前为止,一切都很好。

现在,我们将 bar() 的访问修饰符更新为 private 并独立编译它。

接下来,用新编译的版本替换以前的 Class1 定义( .class 文件 并重新运行程序:

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

上述例外是不言自明的。方法 bar() 现在在 Class1 中是 私有的 。显然,访问是非法的。

4. 操作中的 非法访问错误

4.1.图书馆更新

考虑一个在编译时使用库的应用程序,并且在运行时在类路径中也可以使用该库。

库所有者将公开可用的方法更新为私有,并重建它,但忘记更新此更改的其他方。

此外,在执行时,当应用程序调用此方法(假设公共访问)时,它会遇到 IllegalAccessError。

4.2 接口默认方法

滥用接口中的默认方法是导致此错误的另一个原因。

考虑以下接口和类定义:

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()Super 中是私有的,在 Baeldung 中 是默认的 因此*,*它可以在 MySubClass的层次结构中访问。

因此,编译器不会抱怨,但在运行时,我们会收到错误:

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

在执行期间, 超类方法声明始终优先于接口默认方法。

从技术上讲,应该调用 Super 中的 foobar ,但它是私有的。毫无疑问,会抛出 IllegalAccessError

5. 如何避免?

准确地说,如果我们遇到 IllegalAccessError ,我们应该主要查找类定义中与访问修饰符有关的更改。

其次,我们应该验证用私有访问修饰符覆盖的接口默认方法。

将类级方法公开就可以了。

六,结论

总而言之,编译器将解决大多数非法方法调用。如果我们仍然遇到 IllegalAccesError ,我们需要研究类定义的更改。

这些示例的源代码可 在 GitHub 上获取。