【问题标题】:Why can you not inherit from a class whose constructor is private?为什么不能从构造函数为私有的类继承?
【发布时间】:2020-11-07 22:49:49
【问题描述】:

为什么 Java 不允许从构造函数为私有的类继承?

【问题讨论】:

  • @HovercraftFullOfEels,请参阅 Peter Lawrey 的回答。

标签: java inheritance


【解决方案1】:

Java 不会阻止使用私有构造函数对类进行子类化。

public class Main {
    static class A {
        private A() {
            System.out.println("Subclassed A in "+getClass().getName());
        }
    }

    static class B extends A {
        public B() {

        }
    }

    public static void main(String... ignored) {
        new B();
    }
}

打印

Subclassed A in Main$B

它阻止的是无法访问其超类的任何构造函数的子类。这意味着私有构造函数不能在另一个类文件中使用,并且包本地构造函数不能在另一个包中使用。

在这种情况下,您唯一的选择就是委托。您需要调用工厂方法来创建“超级”类的实例并包装它。

【讨论】:

  • 有什么不对吗?实例化一个嵌套的静态类?它是如何工作的?
  • @jaxox 到 jvm,嵌套类没什么特别的。它们就像任何其他具有但更多元信息的类。因此,您可以创建一个以与任何其他方式相同的方式定义嵌套的类。顺便说一句,静态方法中的匿名类也是静态嵌套类。
  • @PeterLawrey 我有点明白你在说什么,但我还是有点困惑。你不是说Java不允许子类无法访问各自的超类构造函数吗?在您的示例中,B 类无权访问 A 的构造函数。那怎么允许呢?
  • @PeterLawrey 好的,我想对我来说简单的解释是 Java 允许访问嵌套类的私有构造函数。
  • @PeterLawrey 好吧,是的,如果您取下安全装置...有趣的是,IMO,您可以在不首先破坏环境完整性的情况下做些什么。
【解决方案2】:

因为一个类必须调用它的超类构造函数总是。如果无法访问超类构造函数,则无法初始化子类。

更多信息:JLS 8.8.10. Preventing Instantiation of a Class


关于 Brian Roach 的 cmets:

只有当你没有明确地调用并且父类有一个公共或受保护的无参数构造函数(或者没有定义任何在这种情况下有一个默认的 no-参数)。这是必需的,因为......这就是语言的工作方式。子 [classes] 必须调用 [their] parent 的构造函数。

请注意,当您在 Java 中实例化 any 类时,总会隐式调用 Object 构造函数,因为它是所有类的超类。它将执行其default constructor:

public Object() {
}

来自 JLS 链接的注释:

如果隐式声明默认构造函数但超类没有可访问的构造函数(第 6.6 节),则这是编译时错误,该构造函数不接受参数且没有 throws 子句。

【讨论】:

  • 为什么这是一个必要条件,即使它是隐含的?
  • 如果父类声明了一个私有构造函数,那么它就没有任何隐含意义。它需要在子进程中显式调用,但由于构造函数是私有的,所以不能。
  • 除非您自己指定一个,否则每个构造函数中都会隐式调用 super()。
  • 我指的是对 super 的调用是隐式的。为什么必须首先调用 super ?这只是他们设计的方式还是有充分的理由?
  • 只有当你没有明确地调用并且父级有一个公共或受保护的无参数构造函数(或者没有定义任何在这种情况下有一个默认的公共无参数的情况下)时,调用才是隐式的)。这是必需的,因为......这就是语言的工作方式。孩子必须调用父母的构造函数。
【解决方案3】:

如果类的构造函数是私有的,则子类不能调用超级构造函数。 因此继承会失败。

【讨论】:

    【解决方案4】:

    如果您有子类,则子类(子类)构造函数有 2 种可能性: 1. 默认构造函数(无参数构造函数):在这种情况下,默认构造函数会自动尝试调用父类构造函数:这将失败,因为父类构造函数是私有的。 2. 参数化构造函数:当你尝试为具有参数化构造函数的子类创建对象时,你需要通过传递参数或不传递参数来强制从子类构造函数调用父类构造函数:这也会失败,因为父构造函数是私人的。

    由于子类将具有默认构造函数或参数化构造函数,并且不可能拥有它们中的任何一个,因此您不能为具有私有构造函数的父类创建子类。

    【讨论】:

      【解决方案5】:

      是的,在 Luiggi 的回答中添加了一些东西,java 的这个特性在创建单例类时使用,它只允许创建该类的一个实例。

      【讨论】:

      • @Brian 你能告诉我如何在不使构造函数私有的情况下正确地做到这一点吗?
      • Josh Bloch,'Effective Java second edition' - 使用enum。请参阅:stackoverflow.com/questions/5759596/…。如果你没有那本书,那就买吧。对于任何认真对待 java 的人来说,这是一本必读的书
      【解决方案6】:

      这是因为,当我们进行继承时,编译器的工作是通过在每个类构造函数的第一个语句中编写 super() 来使所有类与 Object 类建立直接或间接的关系。 当我们将构造函数设为私有时,这意味着不应从类外部访问它,但是当我们进行继承时,编译器将隐式编写此类语句。

      class SubClassName extends SuperClassName {
        public SubClassName() {
          super();  // which will indirectly going to call the Parent class constructor from outside its scope
        }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-10-07
        • 1970-01-01
        • 2012-01-29
        • 1970-01-01
        • 2020-02-28
        • 2013-08-27
        • 1970-01-01
        相关资源
        最近更新 更多