Подклассы заставляют класс перестать реализовывать интерфейс? - PullRequest
0 голосов
/ 07 января 2011

Вот соответствующие классы и методы:

public class BoardTile implements BoardCoordinate

public class WordPath extends LinkedList<BoardTile>

public void inputCoordinates(Collection<BoardCoordinate> coords)

По сути, здесь происходит следующее: я пишу бота для флэш-игры, и у меня есть интерфейс BoardCoordinate для представления местоположения на доске. Класс, представляющий плитку на плате, называется BoardTile, и, поскольку он знает свое местоположение, он реализует интерфейс BoardCoordinate.

У меня есть список тайлов, представляющих путь по доске, который на самом деле является LinkedList BoardTiles. Наконец, у меня есть метод, в котором я передаю коллекцию BoardCoordinates в мой java.awt.Robot, который вводит запрошенный путь к флэш-игре. Коллекция пропущена ради того, чтобы избежать потенциально уродливой связи между классом скребка экрана и моим пакетом обработки данных.

Итак, вот код ошибки:

/* The highest scoring path found. */
Wordpath highest = null;
/* ...
 * ... find the highest scoring path, etc. 
 */
if (longest != null) {
    screen.inputCoordinates(longest);
}

Ошибка компилятора, которую я получаю, заключается в следующем: метод inputCoordinates (Collection) в типе Screen не применим для аргументов (WordPath).

Но WordPath - это LinkedList BoardCoordinate! А LinkedList - это коллекция! Что тут происходит?

Конечно, я могу прикусить пулю и принять соединение, но это, во-первых, не то, что я хочу делать, а, во-вторых, возможность обучения ...

Ответы [ 2 ]

3 голосов
/ 07 января 2011

A LinkedList<BoardTile> не является Collection<BoardCoordinate>, хотя из-за общей дисперсии.Например, рассмотрим:

collection.add(new OtherBoardCoordinate());

, где OtherBoardCoordinate - это BoardCoordinate, но не BoardTile.Вам бы не хотелось, чтобы один из них был в вашем связанном списке, не так ли?

Если inputCoordinates нужно только прочитать из коллекции, то измените ее подпись следующим образом:

public void inputCoordinates(Collection<? extends BoardCoordinate> coords)

Это в основном говорит: «Аргумент должен быть коллекцией некоторого типа, который расширяет BoardCoordinate, но мне все равно, что это за тип».В inputCoordinates вы не сможете добавлять элементы в коллекцию, что предотвращает проблему, о которой я упоминал в начале.

См. Часто задаваемые вопросы по обобщению Java Angelika Langer для получения дополнительной информации (ищите «подстановочные знаки»).

Альтернативой является WordPath extension LinkedList<BoardCoordinate> вместо этого, и просто происходит для добавления BoardTile значений к нему.(Кстати, вам определенно нужно продлевать LinkedList? Я редко нахожу, что расширяю классы коллекций. Возможно, это уместно в вашем случае.)

0 голосов
/ 07 января 2011
class B extends A { ... }

Collection<A> collectionA;
List<A> listA;
List<B> listB;

listA = listB; // error

collectionA = listB; // error

Даже если B extends A, List<B> является НЕ подклассом List<A>.Кроме того, List<B> не является подклассом Collection<A>.

. На первый взгляд это не интуитивно понятно.Можно подумать об этом:

List<A> listA;
// This declaration means that listA promises to point to a List that
// accepts any instance of 'A' or subclasses of 'A'

List<A> listA = new List<A>();
listA.add(new A()); 
// this is legal because listA promises to put to lists that accept 'A's

List<B> listB = new List<B>();
// new List<B>() creates a list that can hold only instances
// of 'B' or subclasses of 'B'

listA = listB;
// error - broken promise - allowing this assignment would means listA
// will now point to a list that will *NOT* accept an 'A', in direct
// conflict with what is promised by its listA's declaration

listA.add(new A());
// if the above assignment were allowed, then this line would allow
// an `A` to be added to  a list that can only hold `B`s

void myMethod(List<A> listA) { }

myMethod(listB);
// error - broken promise - allowing this parameter would means listA
// (in myMethod) will now point to a list that will *NOT* accept an 'A',
// in direct conflict with what is promised by its listA's declaration

Тот же аргумент верен, если в приведенном выше примере вместо 1011 * подставить Collection<A>.


Возможное решение есть.

Если screen будет читать только из коллекции coords, то использование подстановочного знака должно работать:

public void inputCoordinates(Collection<? extends BoardCoordinate> coords)

inputCoordinate теперь будет принимать аргумент List<BoardTile>.

Однако, есть ловушка.inputCoordinate сможет читать с coords, например, вы можете позвонить coords.get(i), но не сможет вставить что-либо в coords (например, вы не можете позвонить coords.add(). В целом, из-за? extends XXX, вы можете вызывать методы, которые возвращают параметр типа (например, XXX get(...)), но вы не сможете вызывать методы, которые используют параметр типа в качестве типа параметра метода (например, void add(XXX arg)).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...