为什么在构造函数中要调用super()?

97

我正在处理一个继承了 JFrame 的类。

这不是我的代码,它在开始构建GUI之前调用了 super。我想知道为什么要这样做,因为我通常只需访问超类的方法而无需调用 super();


2
附注:扩展 JFrame 可能不是您想要做的事情。扩展意味着 is-a 关系。除非您正在创建新的窗口组件,否则您应该扩展 JComponent - Jeffrey
1
在Java世界中,子类非常尊重它们的父类。如果你想从它们中创建一个新的类,它们首先会创建它们的父类 :) 开玩笑了,https://dev59.com/aGkv5IYBdhLWcg3wkBka#66932288 看起来是正确的答案,因为它描述了为什么Java实现了这种默认行为。 - Alireza Fattahi
8个回答

159
所有有父类的类(Java中定义的每个自定义类)都隐式调用没有参数的super(),因此通常不需要显式调用它。但是,如果父类的构造函数需要参数,并且您希望指定它们,则可以使用带参数的super()调用。此外,在父类的构造函数需要参数且没有默认的无参构造函数的情况下,您需要使用带参数的super()调用。
以下是一个例子,其中对super()进行显式调用可使您更好地控制框架的标题:
class MyFrame extends JFrame
{
    public MyFrame() {
        super("My Window Title");
        ...
    }
}

10
重要提示:在子类构造函数中调用超类构造函数必须放在第一行。有关详细信息,请参见此处:为什么this()和super()必须是构造函数中的第一条语句? - informatik01
1
@Eugene 是的。这也在 Oracle 的官方 Java 教程中的“子类构造函数”一节中提到了(https://docs.oracle.com/javase/tutorial/java/IandI/super.html)。 - informatik01

40
当你没有自己调用时,调用父类空构造函数super()会自动进行,这就是为什么你在代码中从未必须执行它的原因。它已经为你执行了。
当你的超类没有无参构造函数时,编译器将要求你使用适当的参数调用super。编译器将确保你正确地实例化该类。因此这不是你必须过分担心的事情。
无论你在构造函数中是否调用super(),都不会影响你调用父类方法的能力。
顺便说一句,一些人认为出于清晰明了的原因,最好手动调用该方法。

8

以上的答案都没有回答“为什么”的问题。

在这里找到了一个好的解释(链接)

子类可以有自己的私有数据成员,因此子类也可以有自己的构造函数。

子类的构造函数只能初始化子类的实例变量。因此,当子类对象被实例化时,子类对象必须自动执行其中一个超类的构造函数。

您可能还想阅读关于super关键字的所有内容(链接)或观看关于super关键字的所有内容(链接)


1
必须标记为正确答案 - Alireza Fattahi

3
我们可以使用super关键字访问父类元素。假设我们有两个类,父类和子类,它们都有不同的foo方法实现。现在在子类中,如果我们想调用父类的foo方法,我们可以使用super.foo();我们也可以通过super关键字访问父元素。
    class parent {
    String str="I am parent";
    //method of parent Class
    public void foo() {
        System.out.println("Hello World " + str);
    }
}

class child extends parent {
    String str="I am child";
    // different foo implementation in child Class
    public void foo() {
        System.out.println("Hello World "+str);
    }

    // calling the foo method of parent class
    public void parentClassFoo(){
        super.foo();
    }

    // changing the value of str in parent class and calling the foo method of parent class
    public void parentClassFooStr(){
        super.str="parent string changed";
        super.foo();
    }
}


public class Main{
        public static void main(String args[]) {
            child obj = new child();
            obj.foo();
            obj.parentClassFoo();
            obj.parentClassFooStr();
        }
    }

现在从你的代码中得到了一些有价值的东西,可以了解super的含义。 - Hamid khan

1

它只是调用了超类的默认构造函数。


2
不回答问题,问题是“为什么”。不要对非代码文本使用代码格式。 - user207421

1
我们使用super关键字调用超类的成员。
由于子类继承其父类的所有成员(字段、方法、嵌套类),并且构造函数不是成员(它们不属于对象,而是负责创建对象),因此它们不会被子类继承。
因此,如果我们需要创建一个超类的对象,就必须显式地调用父构造函数,以便保持构造函数链的连接。在对象创建时,只能调用一个构造函数。通过super,我们可以在需要时从当前构造函数中调用其他构造函数。
如果您认为这个类没有继承任何其他类,那么请记住每个类默认都遵循对象类。因此,在构造函数中保留super是一个好习惯。
注意:即使在第一条语句中没有super(),编译器也会为您添加它!

注意:即使在你的第一条语句中没有使用super(),编译器也会为你添加它!那么为什么要使用super()呢? - 4ulls

0
由于构造函数不是类的一部分,因此在调用时无法实现它,但是可以通过使用SUPER()在构造函数中调用成员和成员函数。

0

我们可以使用super关键字访问超类成员

如果您的方法覆盖了其超类的某个方法,则可以通过使用关键字super调用被覆盖的方法。您还可以使用super引用隐藏字段(尽管不建议隐藏字段)。考虑这个类,Superclass:

public class Superclass {

    public void printMethod() {
        System.out.println("Printed in Superclass.");
    }
}

// 这里有一个子类,叫做Subclass,它重写了printMethod()方法:

public class Subclass extends Superclass {

    // overrides printMethod in Superclass
    public void printMethod() {
        super.printMethod();
        System.out.println("Printed in Subclass");
    }
    public static void main(String[] args) {
        Subclass s = new Subclass();
        s.printMethod();    
    }
}

在子类中,简单名称 printMethod() 指的是在子类中声明的方法,它覆盖了超类中的同名方法。因此,为了引用从超类继承的 printMethod() 方法,子类必须使用限定名称,就像使用 super 一样。编译和执行子类会打印以下内容:

Printed in Superclass.
Printed in Subclass

1
第一句话是不正确的,而且这些都没有回答问题。 - user207421

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