9

我从 Joshua Bloch 的一次谷歌 I/O 益智演讲中得到了这个。这是代码

 public class Glommer<T> {
      String glom(Collection<?> obj){
         String result = "";
         for(Object o : obj){
              result += o;
         }
         return result;
      }

      int glom(List<Integer> ints){
           int result = 0;
           for(int i : ints){
                result += i;
           }
           return result;
       }

      public static void main(String args[]){
           List<String> strings = Arrays.asList("1", "2", "3");
           System.out.println(new Glommer().glom(strings));
      }

这个 main 方法抛出一个异常,因为new Glommer它是一个原始类型,因此所有泛型都Glommer被删除了,所以它最终调用int glom(List<Integer> ints)而不是String glom(Collection<?> obj).

我的问题是,即使我调用glom()new Glommer<Integer>().glom(strings)不应该调用该int glom(List<Integer> ints)方法,因为由于类型擦除,该方法有效int glom(List ints)并且strings类型List不是Collection

4

3 回答 3

7

被调用的方法是在编译时定义的,而不是在运行时定义的。

如果在构造函数调用中添加参数,编译器将有足够的信息知道它必须调用第一个方法。否则,就好像泛型不存在一样。在这两种情况下,被调用的方法在运行时将始终保持不变。

编辑有些人似乎怀疑,所以这是另一个例子:

public class Test {

    private static void test(Object object) {
        System.out.println("Object method");
    }

    private static void test(Integer integer) {
        System.out.println("Integer method");
    }

    public static void main(String[] args) {
        Object object = Integer.valueOf(0);
        test(object);
    }

}

结果是:

Object method

您将 Integer 传递给您的方法,但编译器在编译时只知道它是一个对象。即使 Object 实际上是一个 Integer,jvm 也不会自动更改方法调用。

于 2012-12-20T17:14:07.320 回答
1

您可以阅读有关原始类型的更多信息以完全理解它

基本上,原始类型用于使用遗留代码,原始类中的几乎所有内容都将成为原始类型,在本例中是这两种方法。

因此,当它是原始的时,有一个方法可以获取一个List和一个,Collection因此它被称为List一个,如果它不是原始的,那么这些方法也不是原始的,它会调用这个,Collection因为它有额外的信息

于 2012-12-20T17:36:44.517 回答
0

这是因为当new Glommer()在没有泛型的情况下调用时Generic<Type>(),所有类型匹配都会从类中删除。

由于 strings 变量是 a List,如果它没有任何泛型<Type>,那么它将匹配glom(List ints). 类型检查直到稍后才完成。

当我们创建new Glommer<AnyType>类型时,所有类型都保留在原地,所以当我们传递我们的strings变量时,它会进行类型检查。编译器现在可以检查它是否是 a List<Integer>,它不是,所以它被传递给glom(Collection<?> obj)方法。

希望这会有所帮助,如果您需要任何澄清,请询问!

于 2012-12-20T17:08:20.897 回答