以下是相关的课程和方法:
public class BoardTile implements BoardCoordinate
public class WordPath extends LinkedList<BoardTile>
public void inputCoordinates(Collection<BoardCoordinate> coords)
基本上,这里发生的是:我正在为flash游戏编写机器人,我有一个名为BoardCoordinate的界面来代表棋盘上的位置。表示电路板上的磁贴的类称为BoardTile,由于它知道其位置,因此它实现了BoardCoordinate接口。
我有一个瓦片列表,它代表了棋盘上的路径,实际上是BoardTiles的LinkedList。最后,我有一个方法,我将BoardCoordinates的集合传递给我的java.awt.Robot,它输入到Flash游戏的请求路径。为了避免屏幕抓取器类和我的数据处理包之间可能的丑陋耦合,Collection被传递。
那么,这是违规代码:
/* The highest scoring path found. */
Wordpath highest = null;
/* ...
* ... find the highest scoring path, etc.
*/
if (longest != null) {
screen.inputCoordinates(longest);
}
我得到的编译器错误是:类型Screen中的方法inputCoordinates(Collection)不适用于参数(WordPath)。
但WordPath是BoardCoordinate的链接列表!而LinkedList是一个集合!这里发生了什么?
当然,我可以咬紧牙关接受耦合,但这首先不是我想做的事情,其次是学习机会......
答案 0 :(得分:3)
由于通用差异,LinkedList<BoardTile>
不是Collection<BoardCoordinate>
。例如,考虑:
collection.add(new OtherBoardCoordinate());
其中OtherBoardCoordinate
是BoardCoordinate
而不是BoardTile
。您不希望链接列表中出现其中一个,是吗?
如果inputCoordinates
只需要从集合中读取,那么请修改其签名:
public void inputCoordinates(Collection<? extends BoardCoordinate> coords)
这基本上说,“论证必须是某种类型的集合,它扩展了BoardCoordinate,但我并不关心这种类型是什么。”在inputCoordinates
范围内,您将无法向集合添加项目 - 防止我在开始时提到的那种问题。
有关详细信息,请参阅Angelika Langer's Java Generics FAQ(查找“通配符”)。
另一种方法是改为WordPath
扩展LinkedList<BoardCoordinate>
,而发生以向其添加BoardTile
值。 (顺便说一下,你肯定需要扩展 LinkedList
吗?我很少发现自己扩展了集合类。虽然它可能适用于你的情况。)
答案 1 :(得分:0)
class B extends A { ... }
Collection<A> collectionA;
List<A> listA;
List<B> listB;
listA = listB; // error
collectionA = listB; // error
即使B extends A
,List<B>
NOT 是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
如果在上面的例子中用Collection<A>
代替List<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(...)
),但是您将无法调用任何使用type参数作为方法参数类型的方法(例如void add(XXX arg)
)。