public class ColTest {
static<T> T wildSub(ArrayList<? extends T> holder, T arg){
T t=holder.get(0);
return t;
}
public static void main(String[] args) {
ArrayList<?> list=new ArrayList<Long>(Arrays.asList(2L,3L,7L));
Long lng=1L;
ColTest.wildSub(list, lng);
}
}
真的很有兴趣为什么这个代码段是合法的,因为wildSub的签名只需ArrayList
个T
或来自T
,而arg属于T
。但<?>
意味着 - 某些特定类型,未知,以及它如何满足编译器?所有类型<?>
并不意味着<? extends Long>
...
答案 0 :(得分:3)
编译器可以自由地推断出与参数类型和返回类型兼容的任何内容。在您的情况下,它始终可以将T
推断为Object
。这将签名转换为
static Object wildSub(ArrayList<?> holder, Object arg)
这意味着它可以将任何ArrayList作为第一个参数,将任何东西作为第二个参数。由于您没有对返回值执行任何操作,Object
将没问题。
答案 1 :(得分:2)
如果你把它当作编译器使用Object在哪里?使用它,它编译的原因是有道理的。这就是它的全部内容。
如果您正在进行任何依赖的操作?作为某个类,如果传入了错误的类,您将在运行时获得强制转换异常。
答案 2 :(得分:1)
作为现有(正确)答案的补充,使其更加清晰:
...
Object result1 = ColTest.wildSub(list, lng); //compiles fine with Sun's javac
// Long result2 = ColTest.wildSub(list, lng); //does not compile without explicit casting
Long result2 = (Long) ColTest.wildSub(list, lng); //compiles fine
...
答案 3 :(得分:1)
这是由于捕获转换。在内部,编译器将表达式Foo<?>
的类型转换为Foo<X>
,其中X
是特定的未知类型。