【问题标题】:How can a Java class have no no-arg constructor?Java 类如何没有无参数构造函数?
【发布时间】:2023-03-12 00:14:01
【问题描述】:

Oracle Java 教程网站有一段让我很困惑:

所有类至少有一个 构造函数。如果一个类没有 显式声明任何,Java 编译器自动提供一个 无参数构造函数,称为 默认构造函数。这个默认 构造函数调用类父的 无参数构造函数,或 Object 如果类没有其他构造函数 父母。如果父母没有 构造函数(对象确实有一个), 编译器将拒绝该程序。

如果所有对象都直接或间接地从 Object 继承,怎么可能引发编译器拒绝所说的?和构造函数是私有的有关系吗?

【问题讨论】:

    标签: java constructor


    【解决方案1】:

    如果所有对象都直接或间接地从 Object 继承,怎么可能引发编译器拒绝所说的?

    我认为您的误解的基础是您认为构造函数是继承的。事实上,构造函数在 Java 中不是继承的。所以考虑下面的例子:

    public class A {
        public A(int i) { super(); ... }
    }
    
    public class B extends A {
        public B() { super(); ... }
    }
    

    班级A

    • 不从Object继承任何构造函数,
    • 没有显式声明无参数构造函数(即public A() {...}),并且
    • 没有默认构造函数(因为它确实声明了另一个构造函数)。

    因此,它只有一个构造函数:public A(int)

    B 类中对super() 的调用尝试在A 中使用不存在的无参数构造函数并给出编译错误。要解决此问题,您要么需要将 B 构造函数更改为使用 A(int) 构造函数,要么在 A 中声明显式无参数构造函数。

    (顺便说一句,构造函数没有必要显式调用超类构造函数......就像我所做的那样。但是很多人认为包含显式调用是一种很好的风格. 如果你忽略它,Java 编译器会插入一个对超类无参数构造函数的隐式调用......如果无参数构造函数不存在或对子类不可见,则会导致编译错误。)

    和构造函数是私有的有关系吗?

    不直接。但是,将构造函数声明为私有将阻止从子类调用该构造函数。

    【讨论】:

    • 很好的解释。使它更清晰。谢谢你,感谢所有回答的人。我接受这个答案不是因为它是唯一正确的答案,而是因为它对我来说是最全面和最清楚的。
    【解决方案2】:

    要理解的关键是,如果类还没有构造函数,则会自动生成无参数构造函数。

    因此很容易创建一个没有无参数构造函数的类。

    【讨论】:

    • 这让我明白了在超类和子类中都没有声明构造函数时不会出现编译错误,因为它会自动为两者生成无参数构造函数。如果在 super 中声明了任何参数构造函数class 那么当子类的默认构造函数寻找超类的无参数构造函数时会导致编译错误,该构造函数不会在这种情况下隐式声明。
    【解决方案3】:

    这个问题最简单的思路如下:

    1. Java 为您创建的任何类提供了非参数构造函数作为默认构造函数。

    2. 当您创建带有参数的自定义构造函数时,Java 会说“嘿,这个类有一个自定义构造函数,所以我不会费心创建/提供默认的非参数构造函数!”

    3. 因此,您的类现在没有默认的非参数构造函数。

    4. 这意味着当您创建一个子类时,基于您的类,您需要显式调用您创建的基于参数的自定义构造函数。

    【讨论】:

    • 解释一个被高度误解的概念的最实用方法!
    【解决方案4】:

    如果你有一个子类的子类

    class A 
    {
        A(int i) {..}
    }
    
    class B extends A 
    {
    }
    

    这里插入B的默认构造函数将尝试调用A的无参数构造函数(不存在),因为它只有一个带一个参数的构造函数

    【讨论】:

    • 既然你没有覆盖 A 中的无参数构造函数,它不应该从 Object 继承它吗?
    • 不,构造函数不会被继承
    【解决方案5】:

    对象的立即 超类必须有一个受保护的或公共的构造函数(或者根本没有构造函数,在这种情况下将创建一个构造函数)。因此,如果我创建一个扩展 Object 的类,并且仅使用私有构造函数,那么将无法扩展我的类。

    【讨论】:

    • 如果两个类在同一个包中,也允许包访问构造函数。
    【解决方案6】:

    是的。私有构造器是一个特殊的实例构造器。它通常用于仅包含静态成员的类中。如果一个类有一个或多个私有构造函数而没有公共构造函数,则其他类(嵌套类除外)不允许创建该类的实例。

    私有构造函数的声明阻止了默认构造函数的自动生成。

    编辑:

    在另一个类中定义的类 称为嵌套类。和其他一样 类的成员,嵌套类可以 是否声明为静态。一种 非静态嵌套类称为 内部阶级。 内部实例 类只能存在于 其封闭类的实例和 可以访问其封闭类的 成员,即使他们被声明 私人

    【讨论】:

      【解决方案7】:

      这意味着,如果你从一行类继承,使默认的无参数构造函数私有(或者它不存在,例如),你的子类必须声明一个构造函数符合其父代的替代构造函数。

      例如,不允许对 Bar 进行如下声明:

      public class Foo {
        private Foo() {  } // or this doesn't even exist
        public Foo(int i) {
        }
      }
      public class Bar extends Foo {
      }
      

      【讨论】:

        【解决方案8】:

        让我在前面提到的一个更有趣的情况下附加一个默认/无参数构造函数不可行的情况,因为除非它被显式声明,否则编译器不能假设它,但它与子类化无关。这是有一个带有final 字段的类的情况,该字段期望构造函数对其进行初始化。例如:

        class Foo extends Object {
            private final Object o;
        
            public Foo(Object o){
               this.o = o;
            }
        }
        

        这里很容易看出,Foo 对象的实例化需要初始化最终字段 o,因此任何对 Foo() 的调用(无论是否直接调用)都注定要失败......让我强调一下超类 (Object) 中的无参数构造函数存在并且可以公开访问,但它是在 Foo 中停用它的最终字段 (o) 的存在。

        【讨论】:

          猜你喜欢
          • 2014-08-31
          • 1970-01-01
          • 1970-01-01
          • 2023-01-01
          • 1970-01-01
          • 2015-01-22
          • 2014-06-18
          • 2019-11-29
          • 1970-01-01
          相关资源
          最近更新 更多