【问题标题】:Java: cannot reference height before supertype constructor has been calledJava:在调用超类型构造函数之前无法引用高度
【发布时间】:2015-08-21 17:35:30
【问题描述】:

我正在尝试使用矩形、三角形和圆形等子类创建一个 Figure 类。但是,当我尝试编译它们时,它们都出现了相同的错误,这让我相信错误出现在 Figure 类中。错误:在调用超类型构造函数之前无法引用高度。

图:

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);
    }

}

非常感谢。

【问题讨论】:

  • 你必须在你的基类构造函数中调用超级构造函数。

标签: java subclass abstract


【解决方案1】:

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

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

【讨论】:

  • 已注意到并已修复,谢谢。我实际上已经有 10 年没有写过 java 了,所以我忘记了那部分。谢谢。
  • 没有问题,删除了我的评论 :)
【解决方案2】:

你需要在 Ellipse 中调用超类构造函数:

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

【讨论】:

    【解决方案3】:

    您需要初始化当前存在于您的 Figure 类中的高度和宽度。您可以通过专门从 Ellipse 调用 Figure 构造函数来做到这一点,就像这样。

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

    super() 方法调用您的 Figure 构造函数,然后它将初始化身高和体重,允许您使用它们来相应地计算 a 和 b。

    【讨论】:

    • 啊,23岁!很棒的数字!
    • 是的,随机默认数字,因为我试图快速回答这个问题。想到的第一件事。
    【解决方案4】:

    每个类都必须调用其超类的构造函数作为其每个构造函数中的第一条指令[1]

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

    这样做是为了正确初始化从超类继承的当前类的逻辑部分。

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

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

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

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

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

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

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

    您尝试这样做的方式,没有宽度和高度的值,因此您不可能在子类中使用它们(例如,width/2 将为零,因为没有任何值可以放入width,因为没有人调用Figure 的构造函数)。创建实例时,没有其他地方会调用设置widthheight 的超类构造函数——因此所有构造函数都必须首先调用它们的超类构造函数。


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

    【讨论】:

      【解决方案5】:

      您需要在Figure: 的每个子类的每个构造函数中首先调用super

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

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

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

      【讨论】:

        【解决方案6】:

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

        补充一点,如果你的超类中有一个非参数化的构造函数,那么你就不必显式调用超类的构造函数。

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

        本页有一个注释:如果构造函数没有显式调用超类构造函数,Java 编译器会自动插入对超类的无参数构造函数的调用。如果超类没有无参数构造函数,则会出现编译时错误。 Object 确实有这样的构造函数,所以如果 Object 是唯一的超类,没有问题。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多