IllegalAccessError和IllegalAccessException的区别

10
考虑以下这一对Throwable

IllegalAccessException扩展 Exception

当应用程序尝试通过反射创建实例(除了数组)、设置或获取字段,或调用方法,但当前执行的方法无法访问指定类、字段、方法或构造函数的定义时,抛出该异常。

IllegalAccessError扩展IncompatibleClassChangeError、LinkageError、Error

如果应用程序尝试访问或修改它无法访问的字段,或调用无法访问的方法,则会抛出该异常。

通常,编译器会捕获此错误;仅当类的定义不兼容地更改时,才可能在运行时出现此错误。

问题

  • 有人能给出每个异常被抛出的代码示例吗?
  • 名称相似是否意味着它们之间有关系,还是仅仅纯属巧合?
  • 是否存在其他的XXXErrorXXXException 组合?这些组合如何相关联?
  • 如果你明确地trycatch其中一个在Exception/Error对中,你是否应该也catch另一个?
3个回答

10

有人能举个例子,展示在哪些情况下会抛出这两种异常吗?

IllegalAccessException 在使用反射调用方法、读写被 Java 可访问性规则禁止的字段时抛出。

IllegalAccessError 不可能被编译正确的 Java 代码抛出。当你加载一个类并试图调用另一个类中被 Java 可访问性规则禁止的方法、读写字段时,会发生该异常。通常编译器会防止这种情况发生,如果出现,说明类存在严重问题。不管怎样,这被认为是一个 "错误",不能恢复,类加载器将拒绝加载有问题的类。

这两个异常名称的相似性是否意味着它们之间有关联,还是纯粹巧合?

这两者之间存在明显的关系。不同之处在于它们发生的情况。

是否存在其他 XXXError 和 XXXException 的组合?这些组合之间有什么关联?

无法确定,请查看 javadocs。

如果在 Exception/Error 对中明确尝试捕获其中一个,是否也应该捕获另一个?

可能不需要。一般情况下,XXXErrorXXXException 会在不同的情况下发生。(这当然适用于反射和类加载器的情况。)此外,通常不应该尝试捕获并从 Error 的子类型中恢复。将 ErrorException 分开的整个意义在于区分不可恢复和(潜在地)可恢复的异常。

在这种情况下,普通应用程序无法通过任何方式从 IllegalAccessError 进行恢复。如果您尝试重复引起问题的类加载器操作,则该问题将再次发生。


很棒的答案!此外,这就是为什么 catch(Throwable t){ } 没有 throw t; 是非常糟糕的消息;意外吞噬错误可能会导致程序惨败,包括拒绝被杀死而不得不强制终止进程。 - Ajax

6
描述已经解释了其中的一些内容:当您使用反射访问不可访问的字段或调用方法时,会抛出Exception;直接这样做会抛出Error(由于某种原因编译器没有捕获它 - 例如当您有一个旧版本的类文件,其中包含您正在尝试使用的私有字段或方法)。

Error通常表示存在严重问题-软件中几乎肯定存在错误。您永远不应该尝试捕获Error。如果您正在捕获XXXException,则没有立即理由也要捕获XXXErrorError文档中说:

Error是Throwable的子类,表示合理的应用程序不应尝试捕获的严重问题。大多数此类错误都是异常条件。ThreadDeath错误虽然是“正常”条件,但也是Error的子类,因为大多数应用程序不应尝试捕获它。

方法不需要在其throws从句中声明任何可能在方法执行期间被抛出但未被捕获的Error子类,因为这些错误是不应该发生的异常条件。

生成IllegalAccessException的示例:通过反射,在类中查找私有方法并尝试调用它。

生成IllegalAccessError的示例:创建两个类并将它们保存在两个源文件A.javaB.java中。在类中,创建一个公共方法,在类中,调用该方法。编译源文件。现在,编辑A.java并将该方法设置为private,仅重新编译A.java(而不是B.java)。现在再次尝试运行;B将尝试调用该方法并抛出IllegalAccessError

还有其他一些看起来相关但名称不完全匹配的XXXException / XXXError对;例如ClassNotFoundException/NoClassDefFoundError


1

java.lang中有几对异常/错误,以下所有内容都涉及反射与直接使用的区别:

IllegalAccessException / IllegalAccessError
InstantiationException / InstantiationError
ClassNotFoundException / NoClassDefFoundError
NoSuchFieldException / NoSuchFieldError
NoSuchMethodException / NoSuchMethodError

其他的例子包括:

java.awt.AWTException / java.awt.AWTError
java.io.IOException / java.io.IOError

直到现在,我不知道这两个错误存在,而且它们在Javadoc(1.6)中没有被其他类引用。因此,我不知道它们是否会在什么时候被抛出。


2
Javadocs只列出可以从可见签名推断出的类的“用途”。错误异常很少(甚至从未)在“throws”子句中声明,因此javadoc工具不知道它们。 - Stephen C

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接