Java:当我实例化抽象类的子类时,它无法识别其超类的构造函数

时间:2011-05-02 20:32:51

标签: java class constructor subclass abstract

我没有很多Java经验,但我看到代码中有一个带有某个构造函数的抽象类,然后是没有构造函数的抽象类的子类。然后,当实例化子类时,它使用其超类构造函数构造。是吗?

我有这个抽象类:

public abstract class Tile{

    public int x;
    public int y;
    public int z;

    protected Color color;
    protected float friction;
    protected float bounce;
    protected boolean liquid;

    public void Tile(int x, int y, int z){
        this.x = x;
        this.y = y;
        this.z = z;
        init();
    }
    abstract protected void init();

这个子类:

public class TestTile extends Tile{
    protected void init(){
        color = Color.RED;
        friction = 0.1f;
        bounce = 0.2f;
        liquid = false;
    }
}

但是当我用这个实例化TestTile时:

Tile tile = new TestTile(0, 0, 0);

init()方法永远不会运行。其中定义的所有值都为null。我尝试制作我可能是子类中的冗余构造函数,它只是用完全相同的参数调用super,但是当我这样做时,即使使用super(x,y,z)内部唯一的语句,它也说:

  

TestTile.java:27:调用super必须是构造函数中的第一个语句

我想制作一堆Tile的子类来实现Tile的属性。如果这不是正确的方法,那么更好的方法是什么?

如果它与任何东西有关,我使用的是32位Ubuntu Linux 11.04。

感谢。

4 个答案:

答案 0 :(得分:6)

您的构造函数不是属性构造函数格式,它是void,使它成为:

public Tile(int x, int y, int z){
        this.x = x;
        this.y = y;
        this.z = z;
        init();
    }

答案 1 :(得分:1)

我没有看到TestTime的构造函数带有三个参数。我根本没有看到任何ctor,这意味着你所拥有的只是编译器给你的默认值。我走得太快而想念它吗?

我建议你注意这点。我重新考虑这个设计:

What's wrong with overridable method calls in constructors?

试试这个 - 它包含了构造函数的修复,并避免了另一个线程指出的问题:

public abstract class Tile{

    public int x;
    public int y;
    public int z;

    protected Color color;
    protected float friction;
    protected float bounce;
    protected boolean liquid;

    public Tile(int x, int y, int z){
        this.x = x;
        this.y = y;
        this.z = z;
    }
}


public class TestTile extends Tile{

    // You're missing this.
    public TestTile(int x, int y, int z)
    {
        super(x, y, z);
        this.init();
    }

    protected void init(){
        color = Color.RED;
        friction = 0.1f;
        bounce = 0.2f;
        liquid = false;
    }
}

答案 2 :(得分:1)

首先,Tile只有一个带x,y,z参数的构造函数,没有默认构造函数,所以你必须在TestTile构造函数中调用super(x,y,z) 。正如slandau所述,“构造函数”具有错误的void返回类型。

TestTile需要声明参数或传递默认值:

public TestTile(int x, int y, int z) {
  super(x, y, z);
}

public TestTile() {
  super(0, 0, 0);
}

在Java中,有很多riscs可以在构造函数中调用抽象方法,另请参见here,实例未正确初始化。你只能安全地调用静态方法(这在这里不起作用)。

public TestTile(int x, int y, int z) {
  super(x, y, z);
  color = Color.RED;
  friction = 0.1f;
  bounce = 0.2f;
  liquid = false;
}

或者您需要在派生类中调用私有方法(从init()中删除抽象Tile):

public TestTile(int x, int y, int z) {
  super(x, y, z);
  init();
}

private void init() {
  color = Color.RED;
  friction = 0.1f;
  bounce = 0.2f;
  liquid = false;
}

您确定会员在这里是正确的实施吗?也许抽象方法(getter)在这里声明一个行为并在子类中实现它可能更好吗?

public abstract class Tile {
  public int x;
  public int y;
  public int z;

  public Tile(int x, int y, int z) {
    this.x = x;
    this.y = y;
    this.z = z;
  }

  public abstract Color getColor();
  public abstract float getFriction();
  public abstract float getBounce();
  public abstract boolean isLiquid();
}

public class TestTile extends Tile {

  public TestTile(int x, int y, int z) {
    super(x, y, z);
  }

  public Color getColor() {
    return Color.RED;
  }

  public float getFriction() {
    return 0.1f;
  }

  public float getBounce() {
    return 0.2f;
  }

  public boolean isLiquid() {
    return false;
  }

}

答案 3 :(得分:0)

构造函数不是继承的,因此在创建TestTile对象时不会调用Tile的三参数构造函数。您需要从TestTile构造函数中显式调用三参数Tile构造函数,就像您说的那样,但是对super(x,x,x)的调用必须是TestTile构造函数的第一个语句。

就像Matt Ball所说的那样,在删除void返回类型之前,你的Tile“构造函数”并不是真正的构造函数。