我不认为我真的了解Java泛型.这两种方法有什么区别?为什么第二个没有编译,错误如下所示.
谢谢
static List<Integer> add2 (List<Integer> lst) throws Exception {
List<Integer> res = lst.getClass().newInstance();
for (Integer i : lst) res.add(i + 2);
return res;
}
Run Code Online (Sandbox Code Playgroud)
.
static <T extends List<Integer>> T add2 (T lst) throws Exception {
T res = lst.getClass().newInstance();
for (Integer i : lst) res.add(i + 2);
return res;
}
Exception in thread "main" java.lang.RuntimeException: Uncompilable source code - incompatible types
required: T
found: capture#1 of ? extends java.util.List
Run Code Online (Sandbox Code Playgroud)
对于第二种编译方法,您必须将结果转换newInstace()
为T
:
static <T extends List<Integer>> T add2 (T lst) throws Exception {
T res = (T) lst.getClass().newInstance();
for (Integer i : lst) res.add(i + 2);
return res;
}
Run Code Online (Sandbox Code Playgroud)
关于这两种方法的区别,让我们忘记实现,只考虑签名.
在编译代码之后,两个方法将具有完全相同的签名(因此如果具有相同的名称,编译器将给出错误).这是因为所谓的类型擦除.
在Java中,编译后所有类型参数都会消失.它们被最通用的原始类型取代.在这种情况下,两种方法都将编译为List add2(List)
.
现在,这将显示两种方法之间的区别:
class Main {
static <T extends List<Integer>> T add1(T lst) { ... }
static List<Integer> add2(List<Integer> lst) { ... }
public static void main(String[] args) {
ArrayList<Integer> l = new ArrayList<Integer>();
ArrayList<Integer> l1 = add1(l);
ArrayList<Integer> l2 = add2(l); // ERROR!
}
}
Run Code Online (Sandbox Code Playgroud)
标记为的// ERROR!
行将无法编译.
在第一种方法中,add1
编译器知道它可以将结果分配给类型的变量ArrayList<Integer>
,因为签名声明方法的返回类型与参数的返回类型完全相同.由于参数是类型ArrayList<Integer>
,编译器将推断T
为ArrayList<Integer>
,这将允许您将结果分配给ArrayList<Integer>
.
在第二种方法中,所有编译器都知道它将返回一个实例List<Integer>
.它不能确定它是一个ArrayList<Integer>
,所以你必须做一个明确的演员,ArrayList<Integer> l2 = (ArrayList<Integer>) add2(l);
.请注意,这不会解决问题:您只是告诉编译器停止抱怨并编译代码.您仍然会收到一个警告(未经检查的强制转换),可以通过使用该方法进行注释来使其静音@SuppressWarnings("unchecked")
.现在编译器会很安静,但你可能仍然会ClassCastException
在运行时获得!
归档时间: |
|
查看次数: |
360 次 |
最近记录: |