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 上获取。