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
级:
- 不从
Object
inheritance任何构造函数, - 没有明确声明一个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构造函数的类很容易。
想到这个问题最简单的方法如下:
-
对于您创建的任何类,非args构造函数由Java提供为默认构造函数。
-
在你用参数创建自定义构造函数的那一刻,Java说“ 嘿,这个类有一个自定义构造函数,所以我不打算创建/提供默认的非args构造函数! ”
-
因此,现在您的类没有默认的非args构造函数。
-
这意味着当您创建子类时,基于您的类,您需要显式调用您创建的基于自定义构造函数的参数。
如果你有一个子类的子类
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
中将其停用。