子类化是否会导致类停止实现接口?

时间:2011-01-07 06:28:45

标签: java inheritance

以下是相关的课程和方法:

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是一个集合!这里发生了什么?

当然,我可以咬紧牙关接受耦合,但这首先不是我想做的事情,其次是学习机会......

2 个答案:

答案 0 :(得分:3)

由于通用差异,LinkedList<BoardTile>不是Collection<BoardCoordinate>。例如,考虑:

collection.add(new OtherBoardCoordinate());

其中OtherBoardCoordinateBoardCoordinate而不是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 AList<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))。

相关问题