覆盖方法中的泛型

时间:2013-04-11 19:50:46

标签: java generics overloading

进入一个有趣的问题;以下类编译:

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

我认为由于类型擦除,这些基本相同。谁知道这里发生了什么?

3 个答案:

答案 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表达式,但此处没有任何表达式。)