接口和对象继承

时间:2016-08-30 09:16:57

标签: java inheritance queue

我有以下代码段。

Queue<Node> queue = new LinkedList<Node>();
queue.add(N);
Node curr = queue.remove();

removeFirst()是LinkedList的一种方法。 remove()是队列的一种方法。 Queue是接口,LinkedList是实现队列的对象。根据我所学到的,当您将对象声明为类型接口然后将其分配给新对象时,该对象必须实现接口中的所有方法,并且可以具有未在接口中指定的其他方法。现在,removeFirst()是未在Queue接口中指定的方法,但它在LinkedList类中指定。但是,当我调用removeFirst()时,我收到一条错误,上面写着“无法找到符号”。我想念的是什么? Queue和LinkedList都来自Java的util库。我用它来编写BFS方法。

3 个答案:

答案 0 :(得分:3)

  • Queue<Node> queue是变量queue编译时类型
  • LinkedList是变量queue运行时类型

编译器检查(在编译时)您尝试分配的运行时类型是否与编译时类型(Queue<Node>)兼容。由于LinkedList实际上是Queue的子类型,编译器允许赋值。

但是,编译器没有任何证据在运行时,queue将公开一个名为removeFirst()的方法,因为实际的赋值是在{{1}时完成的达到了语句。编译器唯一确定的是Queue<Node> queue = new LinkedList<Node>();将在queue接口中定义抽象方法 - 这就是它允许仅调用的原因/ em>那些。

潜在地,Queue完全有可能在执行queue语句之前将其运行时类型更改为不公开removeFirst()方法的内容(例如,某些线程更改它)到queue.removeFirst() - AbstractDeque的另一个子类型,它没有Queue方法。

但是,如果您确实removeFirst()在运行时将拥有queue方法,则可以进行投射:

removeFirst()

这不是很干净,然后您应该考虑((LinkedList<Node>)queue).removeFirst(); 是否是变量的正确编译时类型。

答案 1 :(得分:2)

您的变量属于Queue类型,并且通常在编译时不清楚它后面的实际对象是LinkedList,即使在这种特殊情况下它似乎很明显。因此,编译器必须将此视为错误。

但是你可以通过使用强制转换来告诉编译器你确定该对象是LinkedList

((LinkedList<Node>)queue).removeFirst();

答案 2 :(得分:2)

您的变量queue的类型为Queue,因此当您通过它访问对象时,您只能使用Queue界面中的功能。事实上它'真的'是LinkedList意味着它拥有额外的方法,但事实上你将它视为Queue意味着你有效地承诺不要使用它们。

如果您要创建LinkedList变量并将其指向同一对象,则会看到LinkedList方法。

关键在于,如果在项目生命周期后期更改列表的具体类型,则使用此接口的代码不需要更改,只要您使用的新类型仍然实现{{ 1}}。通过表现为Queue不存在,编译器确保您不会通过使用并非所有队列必然具有的功能从未来维护的角度拍摄自己。