我有一个奇怪的问题,当我试图插入我的程序时,我无法弄明白这个问题。另一个问题是我无法创建一个简单的测试用例,因为每次我尝试它都有效。必须有一些我不知道的并发症。但我会尽可能清楚地描述情况,以防任何人听起来都很熟悉。
我有一个名为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访问控制
...
当且仅当满足以下任一条件时,才能访问类或接口D的字段或方法R:...
- R受保护并在C类中声明,D是C或C本身的子类。
- R既可以是受保护的,也可以是包私有的(即既不公开也不受保护也不是私有),并且由与D相同的运行时包中的类声明。
第一个条款解释了为什么允许Road访问Seed.garden,因为Road是Seed的子类,第二个条款解释了为什么Road $ 4不允许访问它,尽管它与Road在同一个包中,因为它不是在相同的 运行 包,由不同的类加载器加载。限制实际上不是Java语言限制,而是Java VM限制。
所以我的情况的结论是由于Java VM的合法限制而发生异常,我将不得不解决它,可能是通过将字段公开,这在这种情况下不是问题,因为它们是最终的,而不是秘密,或者可能通过道路将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
内部类对另一个类的成员没有更大的访问权限
顶级类,除了那些成员 声明 中
封闭的,封闭的或兄弟的类。这是一种常见的误解
内部类具有对受继承成员的无限制访问权限
它的封闭课程。这不是真的。
我可能会更多地研究这个事实,因为这最初是针对Java 1.2报告的,但我似乎记得从我的阅读中看到今天也是如此。
编辑:
我确认这是真的:
http://docs.oracle.com/javase/tutorial/java/javaOO/summarynested.html
匿名内部类的范围只是定义它的范围。因此即使外部类也可以访问继承的成员。
这是权限错误,因此它取决于您用于运行运行时的框架。
只是为了澄清这确实是这样,让父成员公开,然后尝试运行。如果一切正常,则恢复您的代码,根据您使用的运行时,我们需要配置正确的安全访问。