我真的无法理解为什么我在第一种情况下得到编译错误,而在第二种情况下工作良好。
public class GenericsTest3 {
public static <W> void main(String[] args) {
List<W> l1 = new ArrayList<String>(); // compilation error: Type mismatch: cannot convert from ArrayList<String> to List<W>
doSomething1(new ArrayList<String>()); // works fine
}
public static <L> L doSomething1(List<L> list) {
list.get(0);
list.add(list.get(0));
return list.get(1);
}
}
在我的理解中,在这两种情况下,List都定义为类型参数T/W,那么为什么参数化类型new ArrayList<String>()
在一种情况下失败而在另一种情况下通过呢?
List<W> l1 = new ArrayList<String>();
这里的问题是,您为类型为W的List声明了一个变量l1,但随后将类型为String的(Array)List赋值给它。
你可以直接使用W作为ArrayList的类型参数,也可以删除它的类型参数。
List<W> l1 = new ArrayList<>();
关于你的下一个问题:
doSomething1(new ArrayList<String>());
在这里,您只需创建一个String类型的新数组列表,并将其作为参数传递给doSomething1。在doSomething1,类型参数L因此将是String。
case 1:
List<W> l1 = new ArrayList<String>();
你正在告诉java创建一个泛型列表,并在同一声明中指定数据类型为String。所以编译器很困惑该怎么做。
Case 2:
<L> L doSomething1(List<L> list) method
在这种情况下,java知道泛型列表是输入。所有的动作都在List界面上完成。所以编译。
一个泛型方法(即一个方法的类型参数是专门为该方法声明的,就像你在这里一样)意味着该方法可以被调用,泛型类型参数是该类型参数范围内的任何类型,并且你保证该方法将工作。因此,调用者可以调用您的main
方法,并显式地选择W
作为他们选择的特定类型,并且您保证您的方法将与W
作为该类型一起工作,甚至不知道W
是什么。在这里,这显然不是真的,因为,如果W
被选择为String
以外的任何值,那么List<W> l1 = new ArrayList<String>();
行是无效的。
对于doSomething1
方法也是如此——您保证无论调用者为L
选择什么类型,该方法都将工作。在这里,这是真的。doSomething1
方法内的代码行,无论你用什么代替L
,都可以正常工作。
当你从main
调用doSomething1
方法时,你是调用者,所以你可以为它的L
类型参数选择任何你想要的类型。您选择L
为String
(或者编译器为您推断出这个选择)。这很好。