非法访问错误:类<classname>无法访问其超级接口<interfacename>。

6
我有一个实现IAssembly的类Assembly。
启动应用程序时,我看到以下错误。
Caused by: java.lang.IllegalAccessError: class <Assembly > cannot access its superinterface <IAssembly>
        at java.lang.ClassLoader.defineClass1(Native Method)

汇编代码
class package.Assembly implements IAssembly {

}

IAssembly

interface IAssembly { //note -this is not public, so uses default protected

}

Assembly和IAssembly存在于两个不同的jar包中。这两个jar包被不同的类加载器加载。Assembly类在子类加载器中加载,而IAssembly则在父类加载器中。类加载器使用链接。

通常情况下,这样做是有效的。但当我使用cobertura对jar包进行了检测后运行我的应用程序时,就会出现错误。如果没有检测,一切都正常。cobertura检测导致了这种错误吗?还是说本来就存在错误,只不过cobertura让这种错误更快地暴露了出来。

将接口“public”后,错误消失了。


1
为什么需要使用不同的类加载器来加载JAR文件?你的应用程序是如何部署/运行的?通常最好将东西打包在一起(对于简单的应用程序),或者通过像JNDI和RMI这样的方式访问EJB。我个人会将你的接口和类放在同一个JAR包中。但这只是我的个人意见。 - Chris Aldrich
对我来说,这个消息导致了一个类路径问题,其中一个名为 package_example 的包被定义为:A/package_example/classAB/package_example/classB。当然,为了使其正常工作,AB 都必须在类路径中。 - Evgeni Sergeev
3个回答

8
在使用仪器和多个类加载器时,即使这些加载器被链接在一起,我认为包保护也会失败。这个java.lang.instrument.Instrumentation上的javadoc与您的情况没有直接关系,但它确实描述了一个类似的情况:
代理应该注意确保JAR不包含除用于仪器目的的引导类装入器定义的类或资源之外的任何类或资源。未能遵守此警告可能会导致难以诊断的意外行为。例如,假设存在一个装载器L,L的委托父级是引导类装入器。此外,类C中的方法(由L定义的类)引用非公共访问器类C$1。如果JAR文件包含一个类C$1,则委托到引导类装入器将导致C$1由引导类装入器定义。在这个例子中,可能会抛出IllegalAccessError,从而导致应用程序失败。避免这些问题的一种方法是为仪器类使用唯一的包名称。
Java虚拟机规范指定,后续尝试解析Java虚拟机先前未成功尝试解析的符号引用始终会失败,并且会抛出与初始解析尝试的结果相同的错误。因此,如果JAR文件包含与Java虚拟机先前未能成功解析引用的类对应的条目,则后续尝试解析该引用将失败,并显示与初始尝试相同的错误。
也许可以检查哪个装载器正在找到您的仪器类,并查看是否有一种方法可以使Assembly和IAssembly都从同一个类加载器中加载。

1

我认为您的问题可能是您没有使用兼容版本的IAssembly。因此,即使它在您的类路径中,接口及其实现也不匹配。

如果这是一个类加载器问题,您将会收到一个NoClassDefFoundError错误。


每个类只有一个版本。 - Jayan

1

我只想再添加两个关于这个错误信息的原因:

  1. 如果您的接口可见性不正确,需要将其从protected更改为publicprivate更改为protected等,则也可能会出现此错误。我知道这不是这里的原因,因为提问者已经意识到了,见他的评论。
  2. 在您的IDE中一切都是绿色的,但在您的OSGI环境中却出现了这个错误。您需要检查类是否被导出并且不在私有包中。

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