我花了几个小时阅读关于泛型和类型擦除的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方法实现应该与接口方法具有相同的签名,对吧?我在这里错过了什么?非常感谢任何帮助。
答案 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
。然后,您可以实现该通用接口。