Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Return a nested class type in Java

Tags:

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?

like image 660
miracle2k Avatar asked Apr 08 '09 18:04

miracle2k


1 Answers

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;
    }
}
like image 75
Varkhan Avatar answered Oct 12 '22 09:10

Varkhan