0

I do not have very much Java experience but I see codes where there is an abstract class with a certain constructor and then a subclass of that abstract class without a constructor. Then when the subclass is instantiated it is constructed with its superclass constructor. Is that right?

I have this abstract class:

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

And this subclass:

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

But when I instantiate a TestTile with this:

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

the init() method never runs. All of the values defined inside it are null. I tried making what I though might be a redundant constructor in the subclass which just called super with the exact same parameters, but when I did that, even with super(x, y, z) the only statement inside it, it said this:

TestTile.java:27: call to super must be first statement in constructor

I want to make a bunch of subclasses of Tile which implement the properties of a Tile. If this is not the correct way to do that, what is a better way?

I am using 32-bit Ubuntu Linux 11.04 if it has to do with anything.

Thanks.

Aardbei
  • 221
  • 2
  • 11
  • related http://stackoverflow.com/questions/260666/abstract-class-constructor-in-java look at first answer – Wes May 02 '11 at 20:37

4 Answers4

6

Your constructor is not in propert constructor format, it's void, make it:

public Tile(int x, int y, int z){
        this.x = x;
        this.y = y;
        this.z = z;
        init();
    }
slandau
  • 21,956
  • 39
  • 117
  • 179
1

I don't see a constructor for TestTime that takes three arguments. I don't see any ctor at all, which means that all you have is the default that the compiler gives you. Did I go too fast and miss it?

I'd recommend paying careful attention to this. I'd rethink this design:

What's wrong with overridable method calls in constructors?

Try this - it includes the fix for your constructor and avoids the issue that the other thread points out:

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;
    }
}
Community
  • 1
  • 1
duffymo
  • 293,097
  • 41
  • 348
  • 541
  • 1
    The OP's `Tile` "constructor" has a return type (`void`), so it's not a constructor at all. – Matt Ball May 02 '11 at 20:43
  • 1
    Yes, I'm guilty of 'seeing' what I think should be there rather than what is present. But my ctor comment is still pertinent, even if that correction is made. – duffymo May 02 '11 at 20:43
1

First of all, Tile has only one constructor with the x, y, z parameters, no default constructor, so you have to call super(x, y, z) in the TestTile constructor. As slandau said, the "constructor" has a wrong void return type.

The TestTile needs to declare the parameters or pass default values:

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

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

In Java, there are many riscs to call an abstract method in a constructor, see also here, the instance is not initialized properly. You can only call static methods safe (which will not work here).

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

or you need to call a private method in the derived class (remove the abstract init() from 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;
}

Are you sure members are the right implementation here? Maybe abstract methods (getters) may be better here to declare a behavior and implement it in the subclass?

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

}
Community
  • 1
  • 1
Arne Burmeister
  • 18,467
  • 8
  • 50
  • 89
0

Constructors are not inherited, so the three-parameter constructor of Tile is not invoked when you create your TestTile object. You need to explicitly call the three-parameter Tile constructor from a TestTile constructor, like you said you did try, but that call to super(x,x,x) must be the first statement of the TestTile constructor.

And like Matt Ball said, your Tile "constructor" isn't really a constructor until you remove the void return type.

GriffeyDog
  • 7,882
  • 3
  • 20
  • 32