Java 接口和对象继承

Java 接口和对象继承,java,inheritance,queue,Java,Inheritance,Queue,我有以下代码片段 Queue<Node> queue = new LinkedList<Node>(); queue.add(N); Node curr = queue.remove(); removeFirst是LinkedList的一种方法。remove是队列的一种方法。Queue是接口,LinkedList是实现队列的对象。据我所知,当您将一个对象声明为类型接口,然后将其分配给一个新对象时,该对象必须实现接口中的所有方法,并且可以具有接口中未指定的其他方法。现在,

我有以下代码片段

Queue<Node> queue = new LinkedList<Node>();
queue.add(N);
Node curr = queue.remove();
removeFirst是LinkedList的一种方法。remove是队列的一种方法。Queue是接口,LinkedList是实现队列的对象。据我所知,当您将一个对象声明为类型接口,然后将其分配给一个新对象时,该对象必须实现接口中的所有方法,并且可以具有接口中未指定的其他方法。现在,removeFirst是一个未在队列接口中指定的方法,但它是在LinkedList类中指定的。然而,当我首先调用removeFirst时,我得到一个错误消息,说找不到符号。我错过了什么?队列和LinkedList都来自Java的util库。我用它来编写一个BFS方法。

您的变量是Queue类型的,通常在编译时不清楚它背后的实际对象是否是LinkedList,即使在这种特殊情况下看起来很明显。因此编译器必须将此视为一个错误。

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

((LinkedList<Node>)queue).removeFirst();
变量队列的类型为queue,因此当您通过它访问对象时,只能使用队列接口中的功能。事实上,它“真的”是一个LinkedList,这意味着它有额外的方法,但事实上,您将其视为一个队列,这意味着您实际上承诺不使用它们

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

关键是,如果在项目生命周期的后期更改列表的具体类型,则使用此接口的代码不需要更改,只要使用的新类型仍然实现队列。通过假装removeFirst不存在,编译器确保您不会因为使用并非所有队列都必须具备的功能而从未来维护的角度攻击自己

Queue Queue是变量队列的编译时类型。 LinkedList是变量队列的运行时类型。 编译器在编译时检查您尝试分配的运行时类型是否与编译时类型队列兼容。由于LinkedList实际上是队列的一个子类型,编译器允许赋值

但是,编译器没有任何证据表明,在运行时,queue将公开名为removeFirst的方法,因为实际的赋值是在queue queue=new LinkedList时完成的;语句已到达。编译器唯一确定的是队列将具有队列接口中定义的抽象方法,这就是为什么它只允许调用这些方法

在执行queue.removeFirst语句之前,队列完全可能将其运行时类型更改为不公开removeFirst方法的类型,例如,某些线程将其更改为AbstractDeque—队列的另一个子类型,它没有removeFirst方法

但是,如果您完全确定队列在运行时将具有removeFirst方法,则可以执行强制转换:

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

这并不是很干净,然后您应该考虑队列是否是变量的正确编译时类型。

??您正在没有方法签名的接口上调用removeFirst??奇怪的是,你有一个语法错误,找不到符号?????为什么我投了反对票?我不明白。我问错问题了吗?还是因为这是一个简单的问题而被否决了?因为如果是这样的话,那么这个网站就是在鼓吹它只适合聪明人。没有投你反对票,但你的问题还是很基本的,同时回答起来也很复杂。不知道是否适合。我理解这一点,但我的问题是,在实现软件工程模式(如工厂、适配器等)时,经常会出现这样的情况:我们声明一个变量作为其接口,但将其分配给一个新对象。我们在这个新对象上同时调用特定于对象的方法和接口方法。这怎么可能?我的问题清楚吗?还有,为什么我的问题被否决了?我相信我遵循了正确的格式,提供了相关的代码,提供了我自己的研究,并且非常具体。我认为仅仅因为这对其他人来说是一个简单的问题就否决某人是非常不礼貌的。