进入一个有趣的问题;以下类编译:
public class Test {
public static void main(String[] args) throws Exception {
A a = new A();
B b = new B();
foo(a);
foo(b);
}
private static void foo(A a) {
System.out.println("In A");
}
private static void foo(B b) {
System.out.println("In B");
}
private static class A {}
private static class B extends A {}
}
但是这个失败了:
public class Test {
public static void main(String[] args) throws Exception {
A<String> a = new A<>();
B b = new B();
foo(a);
foo(b);
}
private static void foo(A<String> a) {
System.out.println("In A");
}
private static void foo(B b) {
System.out.println("In B");
}
private static class A<T> {}
private static class B extends A {}
}
出现此错误:
Test.java:8: error: reference to foo is ambiguous, both method foo(A<String>) in Test and method foo(B) in Test match
foo(b);
^
Note: Test.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
1 error
我认为由于类型擦除,这些基本相同。谁知道这里发生了什么?
答案 0 :(得分:3)
原因是您要混合泛型和原始类型(B应声明为class B<T> extends A<T>
或class B extends A<SomeType>
)。
发生这种情况的实际原因隐藏在the JLS, section #15.12.2.7及其后的某个地方 - 祝你好运地表达出来; - )
答案 1 :(得分:2)
在泛型之前,Java有类似
的方法public class Collections
public void sort(List list) {...} [1]
用户代码可能包含
之类的内容public class MyList implements List ... [2]
MyList myList = ...;
Collections.sort(myList); [3]
当将泛型添加到Java时,决定将现有类和方法转换为泛型类,而不会破坏使用它们的任何代码。就困难而言,这是一项伟大的成就,因为语言的复杂和有缺陷是非常昂贵的。
因此[1]
已经过了一般化,但[3]
仍必须按原样编译,而不必遗传[2]
。
黑客入侵§15.12.2.3
Ai可以通过方法调用转换(第5.3节)转换为Si
基本上说如果参数类型(Ai)是raw,那么为了匹配,也要擦除参数类型(Si)。
回到您的示例,我们了解为什么foo(A<String>)
被视为适用于foo(b)
。
然而还有另一个问题 - foo(A<String>)
适用于[§15.12.2.2]吗?规范的字母似乎是“不”的答案。但它可能是规范的一个错误。
答案 2 :(得分:1)
private static class B extends A {}
你在这里省略了A
的类型参数。您可能意味着什么
private static class B<T> extends A<T> {}
此外,B b = new B()
也没有<String>
个参数;你必须这样做
B<String> b = new B<String>();
......最后,
private static void foo(B b) {
System.out.println("In B");
}
应该是
private static void foo(B<String> b) {
System.out.println("In B");
}
通常,如果类型Foo
具有泛型参数,Foo
基本上总是具有类型参数。在这种特殊情况下,class B extends A
没有A
的类型参数,那么B
需要一个类型参数,因此您需要在您提到B
的任何地方使用类型参数。 (该规则的一个主要例外是instanceof
表达式,但此处没有任何表达式。)