【发布时间】:2010-04-13 20:14:00
【问题描述】:
在 Java 中什么时候调用 super()? 我在派生类的一些构造函数中看到了它,但是每个父类的构造函数不是自动调用的吗?为什么需要使用 super?
【问题讨论】:
标签: java
在 Java 中什么时候调用 super()? 我在派生类的一些构造函数中看到了它,但是每个父类的构造函数不是自动调用的吗?为什么需要使用 super?
【问题讨论】:
标签: java
如果你提供这样的类:
public class Foo
{
}
或者这个:
public class Foo()
{
public Foo()
{
}
}
编译器会为此生成代码:
public class Foo()
{
public Foo()
{
super();
}
}
所以,严格来说,对“super()”的调用总是存在的。
在实践中,你应该只在有你想传递给父构造函数的参数的地方调用“super(...)”。
调用“super()”(不带参数)并没有错,但人们会嘲笑你:-)
【讨论】:
Foo 扩展另一个类吗?否则对 super 的调用毫无意义......
您需要在这种情况下使用super():
public class Base {
public Base(int foo) {
}
}
public class Subclass extends Base {
public Subclass() {
super(15);
}
}
这是一个非常人为的示例,但您需要调用super() 的唯一情况是您从不提供默认无参数构造函数的类继承。在这种情况下,您需要从子类的构造函数中显式调用super(),并传入满足基类构造函数所需的任何参数。此外,对super() 的调用必须是继承类构造函数的第一行。
【讨论】:
不需要调用 super()。
来自Accessing Superclass Members:
使用 super(),调用超类的无参数构造函数。使用 super(parameter list),调用具有匹配参数列表的超类构造函数。
注意:如果构造函数没有显式调用超类构造函数,Java 编译器会自动插入对超类的无参数构造函数的调用。如果超类没有无参数构造函数,则会出现编译时错误。 Object 确实有这样的构造函数,所以如果 Object 是唯一的超类,则没有问题。
【讨论】:
如前所述,如果你的构造函数没有显式调用 super() 有或没有一些参数,java 将自动调用超类的默认构造函数。
然而,显式调用 super() 就是这样——显式的。如果您知道超类的构造函数做了一些重要的事情,那么对于维护您的代码的人来说,这是一个有用的提醒,即首先调用 super() (并且可能有副作用)。这甚至可能是在调试时放置断点的有用位置。
【讨论】:
super 的显式调用时,我只是认为他们“非常努力”以确保使用超类的特殊行为(他们并没有意识到它无论如何都会发生)。我想你可以采取你的方法,也可以争辩说,一旦你看到一个类扩展了另一个类,你就应该查看父类,看看那里定义了什么行为。
如果在构造函数中调用 super 失败,那么编译器会在构造函数主体的第一行添加一个无参数的 super 调用作为父构造函数。
和之前发布的代码一样
public class Foo
{
}
或
public class Foo
{
public Foo()
{
}
}
编译器将生成符合 Java 规则的代码。所有的对象都是 java.lang.Object 的子类,所以编译器会像写的一样编译它
// All classes extend Object. This is Java, after all.
public class Foo extends java.lang.Object
{
public Foo()
{
// When constructing Foo, we must call the Object() constructor or risk
// some parts of Foo being undefined, like getClass() or toString().
super()
}
}
但是如果超类没有匹配参数的构造函数,那么你必须调用适当的不匹配的超类构造函数。
public class LightBlue extends java.awt.Color
{
public LightBlue()
{
// There is no Color() constructor, we must specify the suitable super class
// constructor. We chose Color(int red, int green, int blue).
super(172, 216, 230);
}
}
其他时候,也许有一个构造函数与子类构造函数的签名相匹配,但出于某种原因,您不希望将参数直接传递给超类构造函数。
public class HSVColor extends Color
{
public HSVColor(int hue, int saturation, int value)
{
super(...code converting HSV to Red...,
...code converting HSV to Green...,
...code converting HSV to Blue);
}
}
如果您忽略显式指定超类构造函数,则编译器会添加默认的无参数超类构造函数。但是,如果该构造函数不存在,那么编译器将不会编译该类,因为不清楚哪个暴露的构造函数是正确调用的。
这是一种风格考虑,但您可以决定始终包含 super() 调用。如果您选择这样做,那将是因为您想提醒读者基类对象必须作为子类对象的一部分构建,并且您想让特定的超类构造函数显式化。传统上,总是包含 super() 调用是很奇怪的,因为传统上代码只有在与“默认”行为不同时才会被输入。
【讨论】:
当你有一个扩展另一个类的类并且父类没有默认构造函数时,你必须在 Son 的构造函数中使用 super() 来调用父类中的构造函数,并使用如下适当的参数:
class A
{
int a;
A(int value)
{
this.a=value;
System.out.println("A Constructor " + a );
}
}
class B extends A
{
int b;
B()
{
super(5);
this.b=10;
System.out.println("B Constructor " + b);
}
}
如果你想使用“this”调用类中的另一个构造函数,你必须知道你不能将“super”与“this”一起使用。
【讨论】:
我想提供一些迄今为止尚未提及的信息。如果在构造函数中调用this(...),则不能调用super(...); 这还包括Java 自动插入对super(); 的无参数调用
以下示例说明了这一点,包括解释性 cmets:
public class B extends A {
private int x;
public B() {
// Java doesn't call super(); here, because
// of the call to this(...); below.
// You can't call super(...) here either,
// for the same reason.
this(42); // Calls public B(int x) below.
}
public B(int x) {
// Java does call super(); here.
// You can call super(...) here, if you want/need to.
// The net result of calling new B() above is that
// super(...) for class A only gets called once.
this.x = x;
}
}
【讨论】:
当没有调用其他类/超类构造函数时,super() 是隐式的。
【讨论】:
如果你想调用超类的非默认构造函数,或者如果超类没有默认构造函数,你可以使用参数调用 super()。编译器只能插入默认的、无参数的 super() 构造函数。
【讨论】:
因为超类的构造函数不会被自动调用。 例如,可能有多个构造函数,其中一些带有附加参数。所以你并不总是有一个“空”的 super() 语句,而是这样的:
public class DerivedClass extends SomeOtherClass
{
private String anotherParameter;
public DerivedClass(int parameterA, String parameterB, String anotherParameter)
{
super(parameterA, parameterB);
this.anotherParameter = anotherParameter;
}
}
编辑:我显然忘了说(或者我选择的词根本不好,但我不是母语人士,对此感到抱歉)如果超类不接受任何参数,对 super() 的调用将由 java/编译器为您完成。 (现在我重新阅读了我的答案,我可以看到听起来你真的必须调用 super()。)
【讨论】:
虽然super() 对编译器没有任何功能(超类默认构造函数会自动调用),但它确实对我有很大帮助。它对我说:“不要删除空的构造函数。它的存在是有原因的”。
一个完美的例子是您创建 Spring 托管 bean 或 JPA 实体并创建了参数化构造函数。
@Entity
public class Portfolio {
...
public Portfolio() {
super(); // This says to me: DON'T DELETE!
}
/**
* Because there is now a parameterised constructor (me),
* the default constructor no longer exists. This means
* that for this example, you need an empty constructor in place (above)
**/
public Portfolio(String name) {
this.name = name;
}
}
【讨论】:
当我们想从父类继承一些参数时调用Super。这不是强制性的,因为编译器总是调用默认构造函数。如果你想继承一个有一些参数的构造函数,那么你需要调用super。所以你可以使用它。
【讨论】: