我遇到了一个奇怪的问题,我无法弄清楚在尝试插入程序时弹出的问题。另一个问题是我无法创建一个简单的测试用例,因为每次尝试都可以。我一定缺少一些复杂的东西。但是,如果任何人听起来都很熟悉,我将尝试尽可能清楚地描述这种情况。

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

protected 最终花园花园;

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

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

它必须与以下事实有关:子类是由与父类(super class)不同的类加载器加载的,但是我找不到任何正式原因说明该子类不起作用。另外,就像我说的那样,当我尝试通过一个简单的测试用例(包括单独的jar,用不同的类加载器加载子类等)重现问题时,我没有收到错误。

我似乎也不太可能违反访问规则,因为当类由同一个类加载器加载时,它可以工作,并且不会出现编译错误。

我没主意了!有没有人认识到这个问题,或者对我有一些指导,以指导我寻找方向?帮助!

最佳答案

好的,因此在axtavt和其他答复者的帮助下,我弄清楚了问题所在。其他答案有帮助,但他们没有完全正确,这就是为什么我要回答自己的问题。问题出在Java Virtual Machine specification中,定义为“运行时程序包”的概念,如下所示:

5.3创建和加载

...
在运行时,一个类或接口(interface)的确定不仅取决于其名称,还取决于一对:其完全限定的名称及其定义的类加载器。每个此类或接口(interface)都属于一个运行时包。类或接口(interface)的运行时包由包名称以及定义该类或接口(interface)的类加载器确定。
...

5.4.4访问控制

...
当且仅当以下任一条件为真时,类或接口(interface)D才可以访问字段或方法R:...

  • R protected 并在类C中声明,而D是C的子类或C本身。
  • R是 protected 或私有(private)的程序包(即既不是公共(public)的也不是 protected 也不私有(private)的),并且由与D相同的运行时程序包中的类声明。

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

    因此,根据我的情况的结论是,由于Java VM的合法限制而导致发生异常,因此我将不得不通过将字段公开来解决该问题,因为在这种情况下,这不是问题是最终的,而不是 secret 的,或者通过可以访问的Road将Seed.garden导出到Road $ 4。

    谢谢大家的建议和回答!

    关于java - 无法从不同jar中的相同程序包访问父类的 protected 成员,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/10465646/

  • 10-10 01:44