Question

I have a base class that has an abstract getType() method. I want subclasses to be able to implement this method and provide the actual class to use.

In code, something like the following:

public abstract class A {
    public static interface Tile;

    protected abstract Class<Tile> getTileClass();
}

public class B extends A {
    public static class MyTile implements A.Tile { }

    @Override
    protected abstract Class<A.Tile> getTileClass() {
        MyTile t = new MyTile();  // WORKS 
        return MyTile;            // ERROR HERE
    }
}

The problem here is that I get "MyTile cannot be resolved" in the line marked. So I'm trying to return this instead:

return new MyTile().getClass()

but now Eclipse tells me:

Type mismatch: cannot convert from Class<capture#1-of ? extends B.MyTile> to Class<A.Tile>

which I'm not even sure if there's maybe a bug in Eclipse here top (capture#1?).

Next, I'm giving up on interfaces and trying to use an abstract base Tile class. With some help from Eclipse, I end up with the following code that seems to compile:

public abstract class A {
    public static abstract class Tile;

    protected abstract Class<? extends Tile> getTileClass();
}

public class B extends A {
    public static class MyTile exends A.Tile { }

    @Override
    protected abstract Class<? extends A.Tile> getTileClass() {
        return new MyTile().getClass();  // WORKS
        return MyTile;                   // "Cannot be resolved"
    }
}

So I basically seem to have three questions:

1) Is it possible to get this to work with A.Tile being an interface?

2) When using a base class, is Class<? extends X> really the correct way to go?

3) And how can I return my nested B.MyTile class reference from inside the method? Having to do new MyTile().getClass() can't be right, can it?

Was it helpful?

Solution

Generics and covariant type overriding do not work very well together. You have to explicitly declare getTileClass() as returning a class that can be a subclass of A.Tile.

You also can access the class object of MyTile without instanciating it, with MyTile.class.

Try this instead:

public abstract class A {
    public static interface Tile;

    protected abstract Class<? extends Tile> getTileClass();
}

public class B extends A {
    public static class MyTile implements A.Tile { }

    @Override
    protected Class<MyTile> getTileClass() {
        return MyTile.class;
    }
}

Even better would be to make A generic. You still have to use extends in the class type definition, but you can be a bit more specific:

public abstract class A<T extends A.Tile> {
    public static interface Tile;

    protected abstract Class<? extends T> getTileClass();
}

public class B extends A {
    public static class MyTile implements A.Tile { }

    @Override
    protected Class<MyTile> getTileClass() {
        return MyTile.class;
    }
}

OTHER TIPS

public abstract class A {
    public static interface Tile {};

    // I return something that is-a Tile
    protected abstract Tile getTileClass();
}

public class B extends A {
    public static class MyTile implements A.Tile { }

    @Override
    protected abstract Tile getTileClass() {
        return new MyTile();
    }
}

No need for generics, you just want to say that you return a Tile or Tile subclass.

Incidentally, a public static interface in a class is a "code smell"; either make it protected, so only subclasses of A can implement Tile, or put it in its own top-level interface. Putting in a but allowing anyone to implement it sends a mixed message.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top