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

Pep*_*itz 12 java inheritance jar

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

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

保护最终花园;

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

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

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

我也不太可能违反访问规则,因为当类由同一个类加载器加载时它可以工作,而且我没有得到编译错误.

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

Pep*_*itz 8

好的,所以在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虚拟机的合理限制,我将不得不解决它,可能是通过使公共领域,这不是一个问题,在这种情况下,因为他们是最终的,而不是秘密的,或者可能通过道路将Seed.garden出口到Road $ 4,它可以访问.

谢谢大家的建议和解答!