Java: 在调用超类型构造函数之前无法引用高度

Java: cannot reference height before supertype constructor has been called

我正在尝试创建一个 class 图,其中包含矩形、三角形和圆形等子class。然而,当我尝试编译它们时,我在所有这些中都遇到了相同的错误,这让我相信错误在图 class 中。错误:在调用超类型构造函数之前无法引用高度。

图:

public abstract class Figure{
    public double width;
    public double height;

    public Figure(double width, double height){
        this.width = width;
        this.height = height;
    }

    public abstract double area();

    public abstract double perimeter();
}

椭圆:

public class Ellipse extends Figure{
    private double a;
    private double b;

    public Ellipse(){
        a = width/2;
        b = height/2;
    }

    public double area(){
        return (Math.PI * a * b);
    }

    public double perimeter(){
        return (2 * Math.PI * Math.sqrt((Math.pow(a,2) + Math.pow(b,2)))/2);
    }

}

非常感谢。

您需要初始化您的高度和宽度,它们当前存在于您的图中 class。您可以通过专门从 Ellipse 调用 Figure 构造函数来实现,就像这样。

public Ellipse(){
    super(23, 23);
    a = width /2;
    b = height/2;
}

super() 方法调用您的 Figure 构造函数,然后它将初始化高度和重量,使您可以使用它们相应地计算 a 和 b。

您需要在 Ellipse 中调用超级 class 构造函数:

public Ellipse(){
    super(_width, _height)
    a = width/2;
    b = height/2;
}

您需要在 Figure:

的每个子 class 的每个构造函数中首先调用 super
public Ellipse(double ewidth, double eheight){
    super(ewidth, eheight);
    a = width/2;
    b = height/2;
}

这是必要的,因为您使用 widthheight,它们是 Figure 的成员,并且仅在执行 Figure 构造函数时才被初始化,这是 super 调用的作用。您基本上使用了一个未初始化的变量。

那么为什么我调用新参数ewidth而不是width呢?如果我将它们命名为宽度,父 class 中的同名字段将被同名的局部变量遮盖。在您的示例中,这不会成为问题,因为两个构造函数中的代码路径都非常简单,但我想提高人们对此的认识,因为它是隐蔽错误的来源:)

因此您的 Ellipse 构造函数不会调用 Figure 的继承构造函数。然而,您正在尝试使用在 Figure 的构造函数中赋值的 Figure 变量。您需要更新 Ellipse 构造函数以使用值调用 super。我推荐以下。

public Ellipse(int w, int h){
    super(w,h);
    a = width / 2;
    b = width / 2;
}

每个class都必须调用它的superclass的构造函数作为它自己的每个构造函数中的第一条指令[1]

如果 superclass 有一个默认的构造函数(一个没有参数的构造函数),这是隐式完成的。但是如果它只有一个带参数的构造函数,那么你必须自己编写那个调用。您可以通过使用单词 super 并传递适当的参数来做到这一点。

这样做是为了能够正确初始化当前 class 中继承自 superclass 的逻辑部分。

您有两种可能的解决方案:

  1. 将默认构造函数添加到 Figure。也许默认宽度和高度为零:

    public Figure() {
        this( 0.0, 0.0 );
    }
    

    如果宽度和高度有一个合理的默认值,这就有意义了。

  2. 更改子classes 的构造函数,以便它们也接受(至少)宽度和高度:

    public Ellipse(double width, double height){
        super(width, height);
        a = width/2;
        b = height/2;
    }
    

    如果没有合理的宽度和高度默认值,这是有道理的。

按照您尝试这样做的方式,将没有宽度和高度值,因此您不可能在 subclass 中使用它们(例如 width/2 将为零,因为没有任何东西可以在 width 中放置任何值,因为没有人调用 Figure 的构造函数)。当你创建一个实例时,没有其他地方会调用设置 widthheight 的 superclass 构造函数 - 因此所有构造函数都必须首先调用它们的 superclass 构造函数优先。


[1] 也可以调用同一个 class 的其他构造函数之一 - 如果它有多个 - 前提是最终被调用的构造函数调用 supeclass 构造函数。

类似的问题已经有人回答了。 参考这个: java call superclass from a subclass constructor?

要补充一点,如果你的 superclass 中有一个非参数化的构造函数,那么你就不必显式调用 superclass.[=12 的构造函数=]

同时检查一下:https://docs.oracle.com/javase/tutorial/java/IandI/super.html

此页面上有一条注释:如果构造函数没有显式调用 superclass 构造函数,Java 编译器会自动插入对 super[ 的无参数构造函数的调用=21=]。如果 super class 没有无参数构造函数,您将得到编译时错误。 Object确实有这样一个构造函数,所以如果Object是唯一的superclass,没有问题。