为什么调用不同类型的泛型方法会产生编译错误?

时间:2014-01-22 07:40:25

标签: java generics

我正在尝试学习java泛型。我写了一个方法:

public <T> T Gmethod(T a,Collection<T> list){   
        return a;}

使用Gmethod("A",list);调用此功能时,列表的类型为Object

但是使用Gmethod(new Object(),list);调用它,其中list是String的类型是错误, 为什么呢?

3 个答案:

答案 0 :(得分:4)

具有

<T> T method(T a, Collection<T> list) { return a; }

并用

调用它
Collection<Object> list = new LinkedList<>();
method("A", list);

将导致编译器推断类型变量Object的类型T,因为list的类型为Collection<Object>。变量a的类型是String,它是Object的子类型。所以允许这个方法调用。

使用

调用方法
Collection<String> list = new LinkedList<>();
method(new Object(), list);

将再次使编译器推断类型变量T的类型Object,因为现在a的类型为Object。因此,编译器请求参数list的参数为Collection<Object>类型(或子类型)。 Collection<String>不是Collection<Object>的子类型。因此编译器不允许此方法调用。

答案 1 :(得分:2)

当你有一个引用T时,实际的类可以是T或子类。当你有一个<T>时,它必须是那个类而且只有那个类。这是必需的,因为它是引用的容器,修改此容器可以更改原始容器。普通引用不会发生这种情况,因为它是作为副本传递的。

引用按值复制。

String a = "hi";
Object b = a;
b = new Object(); // no problem as `a` is not changed by this.

但是对于容器来说,这种方法不能很好地工作,因为只复制对容器的引用,而不是容器本身。

List<String> a = new ArrayList<>();
a.add("hi");
List<Object> b = (List) a; // compiler warning.
b.add(new Object());       // alters `a` in an incorrect way.
a.get(1);                  // ClassCastException oops.

答案 2 :(得分:1)

正如@Seelenvirtuose和@Peter Lawrey在答案中建议的那样,这是因为编译器为你做的类型推断。

要测试编译器将第一次调用绑定到Object,请尝试使用

class Main{

     public static void main(String[] args){
          Collection<Object> listOfObject = new ArrayList<>();
          Main.<String>method("a",listOfObject); //compile time error here
     }

     public static <T> T Gmethod(T a, Collection<T> coll){
        return a;
     }
}