今天我偶然发现了一些有趣的事情。 假设以下Java 6类:
public class Ereasure {
public Object get(Object o) {
return null; // dummy
}
public static class Derived<T> extends Ereasure{
// (1)
@Override
public Object get(T o) {
return super.get(o);
}
// (2)
/*
@Override
public Object get(Object o) {
return super.get(o);
}*/
}
}
如果您尝试编译上面的示例,编译器会说 Ereasure.java:9:方法不会覆盖或实现超类型的方法 @覆盖 如果你删除@Override注释(这不应该是必要的!),它说 Ereasure.java:8:名字冲突:get(T)在Ereasure.Derived和Ereasure中的get(java.lang.Object)有相同的擦除,但都没有覆盖其他 这有点矛盾,因为T应该设置为Object,因此覆盖父类get方法。
如果你离开(1)未注释并取消注释(2)所以(1)重载(2)它也不起作用。 编译器输出:
Ereasure.java:15: get(T) is already defined in Ereasure.Derived
public Object get(Object o) {
作为结论,T正在被设置为Object,但不能覆盖父get方法。
我现在的问题是,为什么至少有一个例子没有编译?
答案 0 :(得分:7)
您可以在下面的示例中看到为什么不可能做您想做的事情:
public class Erasure {
public void set(Object o) {
return;
}
// method overloading: (which is valid)
public void set(String s) {
return;
}
public static class Derived<S> extends Erasure {
// Oops... which one am I supposed to override?
// (It would actually be overloading if S was a concrete type
// that is neither Object nor String.)
@Override
public void set(S o) { // does not compile
super.set(o);
}
}
}
问题的解决方案是Erasure
应该是参数化类。
答案 1 :(得分:2)
简单地猜测编译器在计算重载时不使用通用视图,这当然是没有意义的,因为有时T可能是Object,而其他类型也是。然后,重叠将依赖于移动目标T,这是完全错误的,特别是如果有多个方法都被称为“获取”但具有不同的单个参数类型。在这种情况下,它只是没有意义,并且猜测他们选择保持简单。
答案 2 :(得分:1)
考虑一个情况,你将getter和setter都重写为泛型。
Derived<String> d = new Derived<String();
Erasure e = d;
e.set(new Object());
String s = d.get(); //Class cast exception
泛型的基本原则是只有在(a)显式强制转换或(b)警告时才会发生类强制转换异常。如果你被允许做你想做的事情,上面会抛出一个例外而没有。