泛型类中的泛型方法和非泛型类中的泛型方法的差异行为

时间:2014-03-10 17:38:22

标签: java generics erasure

我调查一般行为

我注意到了:

public class Hohol1 {
    public class My<T> {
        public <E> void test(Collection<E> es) { System.out.println("Collection<E>");
        }

        public void test(List<Integer> integerList) {
            System.out.println("List<Integer>");
            for (Integer integer : integerList) {
                System.out.println(integer);
            }
        }
    }

    public static void main(String[] args) {
        My my1 = new Hohol1().new My();
        my1.test(new ArrayList<String>() { {add("1");} });
    }
}
上面的

代码返回

Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
    at GenericsTest.Hohol1$My.test(Hohol1.java:22)
    at GenericsTest.Hohol1.main(Hohol1.java:31)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)

但是,如果我My非通用,那么

  public class Hohol1 {
        public class My/*deleted generic type T*/ {
             ....
        }
     }

此代码返回Collection<E>

这对我来说是一种惊喜的行为,我不明白为什么会这样做。

你怎么看?

P.S。我对简洁

使用双括号初始化

1 个答案:

答案 0 :(得分:3)

首先,当您使用内部类My原始形式时,类中的所有内容,包括不相关的指定类型参数(如方法参数List<Integer> integerList)好像他们自己的类型擦除已经到位,例如List integerList

但是,您传递了ArrayList的{​​{1}}(实际上只是ArrayList)的匿名子类String。最具体的方法是test(List<Integer> integerList),因为它被视为ListArrayList肯定是for。在尝试打印Integer的增强型String循环之前,所有内容仍会一直运行,但无法将"1"转换为IntegerClassCastException,所以你得到My

但是如果你使integerList非泛型,那么参数List<Integer>的类型不会被删除。然后,编译器可以看到Collection<E>不匹配,但test(Collection<E> es)匹配,因此"Collection<E>"匹配并打印{{1}}。

原因在JLS, Section 4.8

中指定
  

更准确地说,原始类型被定义为以下之一:

     
      
  • 通过获取泛型类型声明的名称而不带伴随类型参数列表而形成的引用类型。
  •   
     

...

  

未从其超类或超接口继承的原始类型C的构造函数(第8.8节),实例方法(第8.4节,第9.4节)或非静态字段(第8.3节)M的类型是原始的在与C对应的泛型声明中对应于其类型擦除的类型。

还给出了推理:

  

原始类型的使用仅允许作为遗留代码兼容性的让步。在将泛型引入Java编程语言之后编写的代码中使用原始类型是非常不鼓励的。未来版本的Java编程语言可能会禁止使用原始类型。