Java:没有包访问的子类访问

相当新的Java,但我想知道为什么包访问被认为比子类访问“更具限制性”。 也就是说,为子类提供对成员访问权限的每个访问修饰符也为整个包提供访问权限,并且存在提供包访问但不提供子类访问的修饰符。

这不是完全倒退吗? 假设我在某个包中有一个类ControlledInstantiation。 如果我有另一个类AlsoControlledInstantiation扩展ControlledInstantiation,我无法调用ControlledInstantiation的构造函数,除非我将其设置为protected或public。 如果我将其设置为protected,那么包中的任何其他类都可以根据需要经常实例化它。 因此,对于超类(以及语法上的)来说,必须具有可替代性的东西与超类相同或更少的访问权限与提供独特但相关的function的东西相同或更少。 这就像告诉你的孩子他不能玩你的钱包,因为你不会让你的邻居这样做,然后让你的邻居睡在你的房子,因为你的孩子。

所以我想我在问这个决定的动机是什么,我怎么能绕过它呢?

一开始可能看起来倒退,但是想法是Java包应该包含一组在语义上相关的相对内聚的类,这反映在默认的包修饰符中。 然后逻辑是,如果您想更进一步并允许任何包中的子类查看您的成员,您可以声明它们受到保护。 你是否有意义的是,来自外包的子类应该比你自己的包中的任何类(无论是否是子类)更不可信?

Java实际上曾经有一个私有保护修饰符可以实现你所追求的目标,但我想,它被删除了,因为它使人们感到困惑。 我不确定如何在不将每个类/子类对降级到自己的包中的情况下实现这一点。 但这是一个混乱的解决方案,违背了Java的原则,无论如何它都不适用于两个以上类的inheritance层次结构。

你是对的,这个事实有点令人困惑。 以下是我建议的解决方法。

  1. 具有受保护构造函数的示例与方法更相关。 在某些情况下,如果将class标记为abstract ,则可以避免通过不是当前类的子类的包成员访问受保护的构造函数。

  2. 如果您真的希望避免使用包成员访问受保护的方法,那么至少在运行时使用Throwable.getStacktrace()可以解决此问题:

     if(!getClass().isAssignableFrom( Class.forName(new Throwable().getStackTrace()[1].getClassName()))) { throw new IllegalAccessException( "This method can be accessed by subclass only"); } 

你可以密封包装。 请参阅JAR文件规范。