Вернуть вложенный тип класса в Java - PullRequest
5 голосов
/ 08 апреля 2009

У меня есть базовый класс с абстрактным методом getType (). Я хочу, чтобы подклассы могли реализовывать этот метод и предоставлять фактический класс для использования.

В коде что-то вроде следующего:

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

Проблема здесь в том, что я получаю «MyTile не может быть решен» в строке, помеченной. Поэтому я пытаюсь вернуть это вместо:

вернуть новый MyTile (). GetClass ()

но теперь Затмение говорит мне:

Несоответствие типов: невозможно преобразовать из Класс < Захват № 1-из? расширяет B.MyTile > в класс < A.Tile >

что я даже не уверен, есть ли ошибка в Eclipse здесь вверху (захват # 1?).

Далее я отказываюсь от интерфейсов и пытаюсь использовать абстрактный базовый класс Tile. С некоторой помощью Eclipse я получаю следующий код, который, кажется, компилируется:

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

Так что у меня, по-видимому, три вопроса:

1) Можно ли заставить это работать с A.Tile как с интерфейсом?

2) При использовании базового класса Class<? extends X> действительно правильный путь?

3) И как я могу вернуть мою вложенную ссылку на класс B.MyTile изнутри метода? Необходимость сделать new MyTile().getClass() не может быть правильной, не так ли?

Ответы [ 2 ]

6 голосов
/ 08 апреля 2009

Переопределение обобщенных и ковариантных типов не очень хорошо работает вместе. Вы должны явно объявить getTileClass () как возвращающий класс, который может быть подклассом класса A.Tile.

Вы также можете получить доступ к объекту класса MyTile, не создавая его экземпляров, с помощью MyTile.class.

Попробуйте вместо этого:

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

Еще лучше было бы сделать A generic. Вам все еще нужно использовать extends в определении типа класса, но вы можете быть более конкретным:

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;
    }
}
0 голосов
/ 08 апреля 2009
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();
    }
}

Нет необходимости в генериках, вы просто хотите сказать, что вы возвращаете Tile или подкласс Tile.

Между прочим, открытый статический интерфейс в классе - это «запах кода»; либо сделайте его защищенным, чтобы только подклассы A могли реализовать Tile, либо поместите его в собственный интерфейс верхнего уровня. Вставка, но позволяющая кому-либо это реализовать, отправляет смешанное сообщение.

...