【问题标题】:Java: Cannot access protected methods of nested class subclass in subclass of outer classJava:无法访问外部类的子类中嵌套类子类的受保护方法
【发布时间】:2019-07-12 01:12:22
【问题描述】:

我正在分解一个类以允许重用、不同的信息隐藏实现等。

原来是:

public class Outer
{
    public static class Inner
    {
        // ...
        protected static void innerDoSomething()
        {
            // ...
        }
    }

    public outerDoSomething()
    {
        //...   
        Inner.innerDoSomething();
        //...
    }
}

一切都很好,因为允许外部 Outer 类访问嵌套 Inner 类的受保护成员。

但试图这样分解:

public class SuperOuter
{
    public static class SuperInner
    {
        // ...
        protected static void innerDoSomething()
        {
            // ...
        }
    }

    // ...
}

public class SubOuter extends SuperOuter
{
    public static class SubInner extends SuperInner
    {
        // ...
        protected static void innerDoSomethingElse()
        {
            // ...
        }
    }

    public outerDoSomething()
    {
        //...   
        SubInner.innerDoSomethingElse(); // OK
        SubInner.innerDoSomething();     // Error: cannnot access!
        //...
    }
}

innerDoSomething() 不可访问,即使 SubOuter 可以访问 SubInner 的受保护成员,并且 SuperInner 的所有受保护成员都应该是 SubInner 受保护接口的一部分。

使其工作的唯一方法,似乎是为每个方法添加显式委托,例如:

    public static class SubInner extends SuperInner
    {
        // ...
        protected static void innerDoSomethingElse()
        {
            // ...
        }

        protected static void innerDoSomething()
        {
            SuperInner.innerDoSomething();
        }
    }

这很烦人,容易出错且浪费时间。我很想将innerDoSomething() 声明为public,但这并不正确,因为它仅供SubOuter 及其子类使用。

怎么会?受innerDoSomething() 保护的访问不应该被SubOuter 禁止和访问吗?

【问题讨论】:

  • 为什么都是static
  • 在这种情况下,我相信编译器实际上将 SuperInner 指定为 SubInner 的外部父级,它正在从 SubOuter 中剥离范围.如果您删除了扩展程序,它应该可以工作。
  • 我还想补充一点,这不遵循任何官方的 OOP 分解模式。你的方法非常奇怪。我相信可能有更合适的方法来做你想做的事。
  • @Dylan 示例代码中根本没有显示分解模式。我只需要分解 Outer 和 Inner,因为它们都包含需要由不同的子类以不同方式指定的细节。

标签: java inner-classes protected


【解决方案1】:

受保护的方法不能通过变量引用从不同的包中访问。 如果 SuperOuter 和 SubOuter 这两个类在同一个包中,它将起作用。

【讨论】:

  • 实际上似乎是这样:SuperOuter 和 SubOuter 实际上在不同的包中,将 SubOuter 移动到同一个包中神奇地解决了。现在,从逻辑上讲,SuperOuter 和 SubOuter 必须在不同的包中。我猜真正的原始问题是假设对嵌套类的受保护成员的访问被授予作为外部类的一种特殊访问方式,而实际上它是同一个包中类的一种特殊访问方式。
【解决方案2】:

好的,我想我已经解决了,仔细重新阅读了 Gosling 的 The Java Programming Language, 4th ed

  1. SuperOuter 和 SubOuter 位于不同的包中,这在逻辑上应该如此,因此没有整包受保护的成员可访问性到位。

  2. 访问嵌套类的受保护成员实际上是作为外部类和嵌套类之间访问的一种特殊方式(请参阅第 5 章。嵌套类和接口)

  3. 然而,受保护的成员可访问性不仅仅是传递性:除了嵌套/外部授权之外,您需要同时位于子类中并且至少有一个引用该子类的类型(即至少有SubXXX,SuperXXX 是不够的),因为,我引用了3.5 段。受保护的真正含义

每个子类都继承父类的契约并扩展它 以某种方式签订合同。假设一个子类,作为它的一部分 扩展合同,限制受保护的价值 超类的成员。如果不同的子类可以访问 第一个子类的对象的受保护成员,那么它可以 以会破坏第一个子类的方式操纵它们 合同,这是不允许的。

因此,即使在我的情况下,xxxInner 在逻辑上是 xxxOuter 的一部分,并且 SubOuter 扩展了 SuperOuter,因此前者在逻辑上应该能够访问后者的任何受保护成员,但 SubOuter 仍然无法访问 SuperOuter 中 SuperInner 的受保护成员就像它不能接收 SuperInner 作为参数的参数一样,因为该参数可能属于完全不同的层次结构分支。在这种情况下,语言中没有建立连接的具体规定。

这也解释了为什么显式委托起作用:SubOuter 可以访问 SubInner 的受保护成员,因为外部/嵌套授权,并且 SubInner 由于扩展而可以访问 SuperInner 的受保护成员,但 SubOuter 不能访问 SuperInner 的受保护成员,因为后者实际上可能属于不同的层次结构分支,并且建立连接是 SubInner 的工作,可以这么说。

显式委托在逻辑上和语言定义上尊重上述所有内容,因此考虑到适当的访问权限,它应该是“正确”的方式,但由于冗余(如果我调用 SuperInner.在 SubInner.innerDoSomething() 内的 innerDoSomethingElse()?)

最终:例如,我可以使用一些 python 脚本自动执行显式委托(我这样做是为了自动创建具有类似冗余弱点的 Builder 模式),或者干脆放弃增加的访问控制安全性并创建受保护的成员公开。

【讨论】:

    猜你喜欢
    • 2014-04-17
    • 2011-10-16
    • 2015-11-04
    • 1970-01-01
    • 2017-12-09
    • 1970-01-01
    • 2018-07-15
    • 2013-06-08
    • 2015-05-09
    相关资源
    最近更新 更多