实现接口的名称冲突

时间:2017-07-05 05:16:47

标签: java generics interface

我花了几个小时阅读关于泛型和类型擦除的Java文档/ Stackoverflow答案,但我仍然不完全理解这个主题。 问题是实现以下简单的界面:

public interface Stack {
void push(Object element); }

我在一个简单的泛型类中实现了它:

public class NodeStack<T> implements Stack {
private Node<T> top;
private int size;

public void push(T value) {
    if(this.size == 0) {
        this.top = new Node<>(value, null);
    } else {
        this.top = new Node<>(value, this.top);
    }
    this.size++;}
}

当我尝试编译它时,我收到编译器错误消息:

NodeStack.java:10: error: NodeStack is not abstract and does not override abstract method push(Object) in Stack
public class NodeStack<T> implements Stack {
   ^
NodeStack.java:63: error: name clash: push(T) in NodeStack and push(Object) in Stack have the same erasure, yet neither overrides the other

    public void push(T value) {
                ^
where T is a type-variable:
    T extends Object declared in class NodeStack
2 errors

我认为这个问题是由于类型擦除而发生的 - 类中的push方法和接口中的push方法在类型擦除后具有相同的签名。我不明白为什么这会是一个问题。 push方法实现应该与接口方法具有相同的签名,对吧?我在这里错过了什么?非常感谢任何帮助。

3 个答案:

答案 0 :(得分:6)

您正在尝试使用具有对象和通用T的方法签名,两者都不相匹配。

public interface Stack<T> 
{ 
    void push(T element); 
}

现在你的NodeStack类将是

public class NodeStack<T> implements Stack<T> {

答案 1 :(得分:3)

  

类中的push方法和接口中的push方法有   类型擦除后的相同签名。

据我了解,这是问题的症结所在。

您的类将其方法签名与接口的方法签名冲突,但是源级别的类的方法签名比接口上的对象类型更严格/定义。所以他们之前都没有匹配,以及之后由于擦除而匹配,所以你得到编译错误。

它可以获取对象,然后传递给它的T的子类型,并且它无法处理它,但界面说它在源级别它很好。

即使这会起作用,也不是一个坏主意,因为接口说它可以接受任何对象,而实现只能采用T类型。

如果我们允许这个工作,你可以通过使用接口方法存储并获取一个字符串到Stack<Integer>,然后在其他地方对Stack<Integer>的引用最终会得到一个字符串,打破类型安全

答案 2 :(得分:1)

在您的界面中:void push(Object element);,类型为Object的参数,但在您实现界面时,您已更改参数的类型。 Object的子类型并不重要。因为你没有在NodeStack中实现抽象方法,编译器说:

NodeStack is not abstract and does not override abstract method push(Object) in Stack

覆盖方法时,您应该始终记住:

无法更改方法和参数列表的名称,您可以更改访问修饰符。

作为解决方案,将接口设为通用接口,并将参数Object的类型更改为T。然后,您可以实现该通用接口。