无法从不同jar中的同一个包访问超类的受保护成员

我有一个奇怪的问题,当我试图插入我的程序时,我无法弄明白这个问题。 另一个问题是我无法创建一个简单的测试用例,因为每次我尝试它都有效。 必须有一些我不知道的并发症。 但我会尽可能清楚地描述情况,以防任何人听起来都很熟悉。

我有一个名为Seed的基类,它是主应用程序的一部分,由系统类加载器加载。 我有一个插件,其中包含一个类Road,它是Seed的子类。 它在运行时从单独的jar文件加载。 类Road引用了Seed.garden字段,定义为:

保护最终花园;

请注意,我没有收到编译错误。 当插件jar包含在系统类路径中时,我也不会遇到运行时错误。 只有当我的主应用程序使用新的类加载器(系统类加载器作为其父类)加载插件时才会出现错误。 错误是:

java.lang.IllegalAccessError:尝试从类package.Road $ 4访问字段package.Seed.garden

它必须与子类由超类不同的类加载器加载这一事实有关,但我找不到任何官方原因,为什么它不起作用。 另外,就像我说的,当我尝试用简单的测试用例(包括单独的jar,用不同的类加载器加载子类等)重现问题时,我没有得到错误。

我也不太可能违反访问规则,因为当类由同一个类加载器加载时它工作,我不会遇到编译错误。

我没有想法! 有没有人认识到这个问题,或者有一些指示我的方向可以看? 救命!

好的,所以在axtavt和其他受访者的帮助下,我弄清楚问题是什么。 其他答案有所帮助,但他们并没有完全正确,这就是为什么我回答我自己的问题。 问题结果是“运行时包”的概念,在Java虚拟机规范中定义如下:

5.3创建和加载

…在运行时,类或接口不是由其名称单独确定,而是由一对确定:它的完全限定名称及其定义的类加载器。 每个这样的类或接口都属于单个运行时包。 类或接口的运行时包由包名称和类或接口的类加载器定义。 …

5.4.4访问控制

…当且仅当满足以下任何条件时,字段或方法R才能被类或接口D访问:…

  • R受保护并在C类中声明,D是C或C本身的子类。
  • R既可以是受保护的,也可以是包私有的(即既不公开也不受保护也不是私有),并且由与D相同的运行时包中的类声明。

第一个条款解释了为什么允许Road访问Seed.garden,因为Road是Seed的子类,第二个条款解释了为什么Road $ 4不允许访问它,尽管它与Road在同一个包中,因为它不是在同一运行时包中,由不同的类加载器加载。 限制实际上不是Java语言限制,而是Java VM限制。

所以我的情况的结论是由于Java VM的合法限制而发生exception,我将不得不解决它,可能是通过将字段公开,这在这种情况下不是问题,因为它们是最终的,而不是秘密,或者可能通过道路将Seed.garden出口到Road $ 4,它可以访问。

谢谢大家的建议和解答!

听起来你有一个类身份危机,有两个不同的类加载器在类层次结构中加载相同的类或类似。 阅读java类加载器上的一些内容。 这是一个很好的介绍,对于“类身份危机”,见图2: http : //www.ibm.com/developerworks/java/library/j-dyn0429/

我应该补充一点,道路4美元是一个匿名的内部道路……

其他人认为这也是1998年的一个错误:

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4116802

除了在封闭,封闭或兄弟类中声明的那些成员之外,内部类对顶级类的成员没有更大的访问权限。 一个常见的误解是内部类对其封闭类的inheritance成员具有不受限制的访问权限。 这不是真的。

我可能会更多地研究这个事实,因为这最初是针对Java 1.2报告的,但我似乎记得从我的阅读中看到今天也是如此。

编辑:

我确认这是真的:

http://docs.oracle.com/javase/tutorial/java/javaOO/summarynested.html

匿名内部类的范围只是定义它的范围。 因此即使外部类也可以访问inheritance的成员。

这是权限错误,因此它取决于您用于运行运行时的框架。 只是为了澄清这确实是这样,让父成员公开,然后尝试运行。 如果一切正常,则恢复您的代码,根据您使用的运行时,我们需要配置正确的安全访问。