什么时候超类没有默认构造函数?

rwu*_*wu6 4 java inheritance constructor class

根据构造函数Java教程:

您不必为您的类提供任何构造函数,但在执行此操作时必须小心.编译器自动为没有构造函数的任何类提供无参数的默认构造函数. 此默认构造函数将调用超类的无参数构造函数.在这种情况下,如果超类没有无参数构造函数,编译器将会抱怨,因此您必须验证它是否存在.如果你的类没有显式的超类,那么它有一个隐式的超类Object,它有一个无参数的构造函数.

如果你有一个没有显式默认构造函数的超类A,
并且子类B 扩展了没有显式默认构造函数的A,

在驱动程序类的main方法中你
A obj1 = new A();
会创建一个默认构造函数,
它将调用Object类的默认构造函数,对吗?

但是如果
B obj2 = new B();
按照教程进行操作,将生成B的默认构造函数,
构造函数将调用超类的无参数构造函数,而超类
将依次调用Object中的构造函数.

那么什么时候超类没有无参数构造函数呢?

Edw*_*rzo 6

默认构造函数由编译器在您未提供时定义.

所以这

public class A{}
Run Code Online (Sandbox Code Playgroud)

将在某种程度上由编译器表示为:

public class A
  public A() {
    super(); //invokes Object's default constructor
  }
}
Run Code Online (Sandbox Code Playgroud)

由于我的定义A没有定义明确的构造函数.

在上面的示例中,隐式A扩展,并且编译器会自动调用默认构造函数.任何可能扩展的类都是如此,例如:ObjectObject'ssuper()A

public class B extends A {}
Run Code Online (Sandbox Code Playgroud)

将由编译器实现有点像:

public class B extends A {
   public B() {
      super(); //invokes A's default constructor
   }
}
Run Code Online (Sandbox Code Playgroud)

你可以看到最终会链接Object默认构造函数,然后A是默认构造函数,最后B是默认构造函数.

>那么超类何时才会有无参数构造函数?

当您明确定义一个时,它将没有no-arg构造函数.例如,如果我将我的定义更改A

public class A {
   public A(String name){}
}
Run Code Online (Sandbox Code Playgroud)

然后A不再有默认构造函数,我不能再这样做了

public class B extends A {
   //Uh oh, compiler error. 
   //Which parent class constructor should the compiler call?
} 
Run Code Online (Sandbox Code Playgroud)

现在B必须通过明确说明要使用哪一个来明确地将正确的构造函数从其父类链接起来.例如

public class B extends A {
   B() {
     super("B"); //Now the compiler knows which constructor to invoke
   }
}
Run Code Online (Sandbox Code Playgroud)

Java反编译器演示

事实上,您可以使用JDK附带的工具来演示所有这些.您的JDK bin目录中有一个名为的程序javap.这是Java Decompiler工具,它允许您查看编译器生成的代码.

您可以编译我的示例,然后反编译它们以查看生成的代码,例如

javac A.java
javap A
Run Code Online (Sandbox Code Playgroud)

反编译器会告诉你:

public class A {
  A();
}
Run Code Online (Sandbox Code Playgroud)

这清楚地表明编译器添加了一个默认构造函数.

您可以反汇编类以查看字节代码.

javac B.java
javap -c B
Run Code Online (Sandbox Code Playgroud)

它将显示它如何调用父类的默认构造函数

class B extends A {
  B();
    Code:
       0: aload_0
       1: invokespecial #1 // Method A."<init>":()V
       4: return
}
Run Code Online (Sandbox Code Playgroud)

如果我在A构造函数中添加一个默认参数,您将看到编译器不再提供默认构造函数,它只提供我明确定义的那个:

class A {
    A(String name){}
}
Run Code Online (Sandbox Code Playgroud)

然后我就能做到

javac A.java
javap A
Run Code Online (Sandbox Code Playgroud)

它产生了

class A {
  A(java.lang.String);
}
Run Code Online (Sandbox Code Playgroud)

这表明您在原始问题中引用的规范中所读到的内容是正确的.


das*_*ght 1

main驱动程序类的方法中你做

A obj1 = new A();
Run Code Online (Sandbox Code Playgroud)

将创建一个默认构造函数

在驱动程序的方法中您无法执行任何操作main来创建默认构造函数。如果定义了,就可以使用;如果未定义,则会出现编译错误。

那么什么时候超类不会有无参构造函数呢?

当它有其他构造函数时,所有这些构造函数都带有一些参数。这是一个例子:

class SuperA {
    public SuperA(String str) { ... }
    public SuperA(int num) { ... }
}
Run Code Online (Sandbox Code Playgroud)

上面SuperA有两个构造函数 - 一个采用String,另一个采用int。它们都不是默认的,因为它们带有参数。

如果创建派生类DerivedB extends SuperA并且不定义任何构造函数,则会出现编译错误。