这是Java代码:
public interface myInterface<T> {
void doSomething(T yes);
}
private static class myInterfaceImpl<T> implements myInterface<T>{
@Override
public void doSomething(Object yes) {
}
}
即使我认为该类没有从接口重写该方法,也可以编译该东西。通过类型推断,我将假定类型参数T始终等于Object,因为该类从接口实现方法,在接口中它明确将Object声明为参数。覆盖方法中带有(T yes)的版本也可以使用,但这对我来说很明显。您能告诉我我所举的例子为什么如此吗?
谢谢。
答案 0 :(得分:4)
在这里,类型擦除是Java在JDK 1.5中引入泛型时用于向后兼容的机制,使事情有点违反直觉。
通常,人们希望重写方法的签名必须完全匹配。事实并非如此。虽然完全匹配签名肯定会覆盖该方法,但签名的 erasure 也将会覆盖该方法。 JLS, Section 8.4.8.1指出:
在类C中声明或继承的实例方法m C ,从C重写在类A中声明的另一个方法m A ,前提是以下所有条件均成立:
-snip
m C 的签名是m A 的签名的子签名(第8.4.2节)。
然后section 8.4.2指出:
方法m 1 的签名是方法m 2 的签名的子签名:
- 具有相同的签名
m 2 与m 1 或
m 1 的签名与m 2 的签名的擦除(第4.6节)相同。
由于对T
的擦除为Object
,因此允许使用采用Object
的方法重写(在此实现)该方法。如果您在界面中的T
上设置了上限,那么您将无法再使用Object
覆盖该方法。一定是那个上限,就是擦除。
// Example of erasure with upper bound
interface myInterface<T extends Number> {
void doSomething(T yes);
}
class myInterfaceImpl<T extends Number> implements myInterface<T>{
@Override
public void doSomething(Number yes) {
}
}
请注意,此处不允许参数相反。使用上限时,您不能使用采用参数类型超类型的方法来覆盖doSomething
,例如Object
。
// A compiler error occurs here when the erasure is Number.
@Override
public void doSomething(Object yes) {
}
答案 1 :(得分:1)
因此,您偶然发现了协方差和相反方差。 假设您有:
IMyInterface<T> {
void foo(T o);
}
然后您实现
class A implements IMyInterface<Integer> {
void foo(Integer o) { ... }
}
您也可以写:
class A implements IMyInterface<Integer> {
void foo(Number o) { ... }
}
class A implements IMyInterface<Integer> {
void foo(Object o) { ... }
}
因为类型T的 param o 被保证为整数 -> o 也保证是数字或对象 ->因为整数扩展了数字扩展了对象
所以您正在减弱类型! 这就是您的代码。
答案 2 :(得分:0)
我可能已经找到了answer:
在类型擦除过程中,Java编译器将擦除所有类型参数,如果类型参数是有界的,则将每个参数替换为其第一个边界。如果类型参数是无界的,则将其替换为对象。
请考虑以下表示单个链接列表中节点的通用类:
public class Node<T> {
private T data;
private Node<T> next;
public Node(T data, Node<T> next) {
this.data = data;
this.next = next;
}
public T getData() { return data; }
// ...
}
由于类型参数T是无界的,因此Java编译器将其替换为Object:
public class Node {
private Object data;
private Node next;
public Node(Object data, Node next) {
this.data = data;
this.next = next;
}
public Object getData() { return data; }
// ...
}
在下面的示例中,通用Node类使用一个有界的类型参数:
public class Node<T extends Comparable<T>> {
private T data;
private Node<T> next;
public Node(T data, Node<T> next) {
this.data = data;
this.next = next;
}
public T getData() { return data; }
// ...
}
Java编译器将绑定类型参数T替换为第一个绑定类Comparable:
public class Node {
private Comparable data;
private Node next;
public Node(Comparable data, Node next) {
this.data = data;
this.next = next;
}
public Comparable getData() { return data; }
// ...
}
感谢@Oleksandr。