fre*_*low 13 java generics wildcard
打印范围内的所有元素的以下方法之间是否存在实际差异?
public static void printA(Iterable<?> range)
{
for (Object o : range)
{
System.out.println(o);
}
}
public static <T> void printB(Iterable<T> range)
{
for (T x : range)
{
System.out.println(x);
}
}
Run Code Online (Sandbox Code Playgroud)
显然,printB
涉及对Object的额外检查演员(见第16行),这对我来说似乎相当愚蠢 - 不是所有的东西都是对象吗?
public static void printA(java.lang.Iterable);
Code:
0: aload_0
1: invokeinterface #18, 1; //InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
6: astore_2
7: goto 24
10: aload_2
11: invokeinterface #24, 1; //InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
16: astore_1
17: getstatic #30; //Field java/lang/System.out:Ljava/io/PrintStream;
20: aload_1
21: invokevirtual #36; //Method java/io/PrintStream.println:(Ljava/lang/Object;)V
24: aload_2
25: invokeinterface #42, 1; //InterfaceMethod java/util/Iterator.hasNext:()Z
30: ifne 10
33: return
public static void printB(java.lang.Iterable);
Code:
0: aload_0
1: invokeinterface #18, 1; //InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
6: astore_2
7: goto 27
10: aload_2
11: invokeinterface #24, 1; //InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
16: checkcast #3; //class java/lang/Object
19: astore_1
20: getstatic #30; //Field java/lang/System.out:Ljava/io/PrintStream;
23: aload_1
24: invokevirtual #36; //Method java/io/PrintStream.println:(Ljava/lang/Object;)V
27: aload_2
28: invokeinterface #42, 1; //InterfaceMethod java/util/Iterator.hasNext:()Z
33: ifne 10
36: return
Run Code Online (Sandbox Code Playgroud)
在您的示例中,泛型类型仅用于签名的一个位置.在这种情况下,类型对调用者T
没有优于通配符的优势.在您的示例中,该类型对于方法的实现者也没有任何优势.
我发现调用者更容易理解通配符版本,因为它明确地说"我根本不关心类型".
在你的例子中,这checkcast
确实是多余的.如果T
是有限的,那将是必需的T extends Number
.然后需要checkcast Number
,因为局部变量x
将是类型Number
,但Iterator.next()
方法仍然返回Object
.似乎Java编译器不打算优化演员表.JIT可能会在运行时这样做.
更新:
如果泛型类型在很多斑点,就像在克莱的答案时,你别无选择,只能使用一个泛型类型T
,否则编译器看到的参数类型/返回类型之间没有连接(任意两个通配符是不同的编译器) .
边界情况是签名仅在一个位置具有类型,但实现需要它是通用类型而不是通配符.想一个void swap(List<T> list, int a, int b)
方法.它需要从列表中取出元素并将它们重新放入.IIRC,Effective Java建议使用带有通配符的公共方法,以及带有包含实际实现的类型的内部帮助器方法.这样,用户获得了一个简单的API,并且实现者仍然具有类型安全性.
public void swap(List<?> list, int a, int b){
swapHelper(list, a, b);
}
private <T> void swapHelper(List<T> list, int a, int b){
...
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
3597 次 |
最近记录: |