构造函数中是否需要使用super()?

186

如果我没有在子类的构造函数中定义,那么编译器不是会自动添加它吗?

这意味着我甚至不需要关心它?有些文章将其列出。

如果我有一个带参数的构造函数,那么这将成为构造函数,还是要使用不带参数列表的构造函数?

6个回答

262

首先是一些术语:

  • 无参构造函数:没有参数的构造函数;
  • 可访问的无参构造函数:超类中对子类可见的无参构造函数。这意味着它可以是public或protected,如果两个类在同一个包中,则是包访问权限;以及
  • 默认构造函数:当类中没有显式构造函数时,编译器添加的公共无参构造函数。

因此,所有类都至少有一个构造函数。

子类的构造函数可能会指定要调用哪个超类构造函数,然后再执行子类构造函数中的代码。

如果子类构造函数没有指定要调用哪个超类构造函数,则编译器将自动调用超类中可访问的无参构造函数。

如果超类没有无参构造函数或者该构造函数不可访问,则在子类构造函数中不指定要调用的超类构造函数是一个编译错误,因此必须指定。

例如:

public class Base { }
public class Derived extends Base { }

这样做是可以的,因为如果你没有显式地添加构造函数,Java会为你添加一个公共默认构造函数。

public class Base { }
public class Derived extends Base { public Derived(int i) { } }

也可以。

public class Base { public Base(String s) { } }
public class Derived extends Base { }

以上是编译错误,因为 Base 没有默认构造函数。

public class Base { private Base() { } }
public class Derived extends Base { }

这也是一个错误,因为Base的无参构造函数是私有的。


54
所以,我猜测标题中的问题的答案是“是的,在子类构造函数中包含super()是不必要的”,因为super()是对“可访问的无参构造函数”的调用。 - flow2k
2
以上是编译错误,因为Base没有默认构造函数。应该修改为“以上是编译错误,因为Base没有无参构造函数。” - Anup Verma
1
取决于你的想法。我认为虽然不是必要的,但我也不会说它是不必要的。 - ahsan.dev
@flow2k 这不是一个简单的是或否的问题。在某些情况下,它是不必要的,就像他的例子所示,在某些情况下则是必要的。如果没有指定super()或者super(...),那么它将自动插入到this(...)中。如果超类不包括无参构造函数或者它不可访问,则编译器会报错。在这种情况下,需要使用super(...)并指定构造函数。因此,在某些情况下可能不存在可访问的无参构造函数,这种情况下就需要使用带参数的super。 - JustAFellowCoder
请注意,如果超类只有一个私有构造函数,则无法扩展该类(或在没有反射的情况下实例化该类),因为没有可访问的构造函数。 - JustAFellowCoder

63

1
如果超类没有任何构造函数,编译器将提供默认构造函数。提供的构造函数将具有与超类访问级别相同的访问级别。 - JonyD

29

调用无参数的超类构造函数只是浪费屏幕空间和程序员的时间。不管你是否编写,编译器生成的代码都是完全相同的。

class Explicit() {
    Explicit() {
        super();
    }
}

class Implicit {
    Implicit() {
    }
}

更新(2018年12月):

在IDE中,显式使用 super() 可以帮助浏览源代码。

截至2018年12月,无论是Eclipse还是IntelliJ都没有提供任何方便从派生类的构造函数导航到基类构造函数的方法。


空的无参隐式构造函数也是不必要的。 - Jon
5
在这种情况下,是的。但如果你有带参数的构造函数,那么无参构造函数就不会默认创建。 - Eric Wilson

8

即使您没有调用它,子类默认构造函数仍会调用父类的默认构造函数。

主要

public class Main {

    public static void main(String[] args) {
        A a = new B();
    }
}

A

public class A {

    public A() {
        System.out.println("A");
    }
}

B

public class B extends A {

    public B() {
        System.out.println("B");
    }
}

打印。
A
B

1
任何类的构造函数如果没有显式地调用super([arguments]),则始终会调用"super()",我们在编程时要记住访问超类构造函数...当我们不扩展任何特定类时,自动扩展java.lang.Object类。

-2
abstract class Book
 {
String title;
String author;
Book(String t,String a){
    title=t;
    author=a;
}
abstract void display();

}    

如果超类可以有一个无参构造函数,最好有一个无参构造函数,否则您必须传递带参数的超级构造函数。
如果超类没有无参构造函数或者它不可访问,则在子类构造函数中不指定要调用的超类构造函数是编译器错误,因此必须指定。
class MyBook extends Book{   
int price ;
public  MyBook(String t,String a,int price){
     super(t,a);
    this.price=price;
}

public void display(){
    System.out.println("Title: "+title);
 System.out.println("Author: "+author); 
System.out.println("Price: "+price);

}

}


1
抱歉,您提供的内容不符合逻辑。 - user207421

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接