Java类如何没有no-arg构造函数?

Oracle Java教程网站的这一段令我困惑:

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

如果所有对象直接或间接地从Objectinheritance,那么如何引出编译器拒绝? 它是否与私有的构造函数有关?

如果所有对象直接或间接地从Objectinheritance,那么如何引出编译器拒绝?

我认为你误解的基础是你认为构造函数是inheritance的。 实际上,构造函数不是用Javainheritance的。 请考虑以下示例:

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

A级:

  • 不从Objectinheritance任何构造函数,
  • 没有明确声明一个no-args构造函数(即public A() {...} ),和
  • 没有默认构造函数(因为它确实声明了另一个构造函数)。

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

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

(顺便说一句,构造函数没有必要显式地调用超类构造函数……就像我已经完成的那样。但是很多人认为包含显式调用是一种好的方式。如果你把它遗漏掉,那么Java编译器插入对超类no-args构造函数的隐式调用…如果no-args构造函数不存在或子类不可见,则会导致编译错误。)

它是否与私有的构造函数有关?

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

要理解的关键是,如果类没有构造函数,则只会自动生成no-arg构造函数。

因此,创建一个没有no-arg构造函数的类很容易。

想到这个问题最简单的方法如下:

  1. 对于您创建的任何类,非args构造函数由Java提供为默认构造函数。

  2. 在你用参数创建自定义构造函数的那一刻,Java说“ 嘿,这个类有一个自定义构造函数,所以我不打算创建/提供默认的非args构造函数!

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

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

如果你有一个子类的子类

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

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

对象的直接超类必须具有受保护或公共构造函数(或者根本没有构造函数,在这种情况下将创建一个)。 所以,如果我创建一个扩展Object的类,只使用私有构造函数,那么任何东西都无法扩展我的类。

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

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

编辑:

在另一个类中定义的类称为嵌套类。 与类的其他成员一样,嵌套类可以声明为静态或不声明。 非静态嵌套类称为内部类。 内部类的实例只能存在于其封闭类的实例中,并且即使它们被声明为私有,也可以访问其封闭类的成员

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

例如,不允许使用以下Bar的声明:

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

让我附上所有上述一个有趣的案例,其中default / no-arg构造函数是不可行的,在某种意义上,除非它是显式声明的,否则编译器不能假设它,但它与子类没有任何关系。 这是一个带有final字段的类的情况,该字段需要构造函数初始化它。 例如:

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

在这里很容易看到Foo对象的实例化需要初始化最终字段o所以任何Foo()调用 – 直接或不是 – 都注定要失败……让我强调一下no-arg构造函数超类( Object )存在且可公开访问,但最终字段( o )的存在在Foo中将其停用。