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);
}
}
Really interested why this snippet is legal, because the signature of wildSub takes only ArrayList
of T
or derived from T
, and arg of type T
. But <?>
means - some specific type, not known, and how it can satisfy the compiler? After all type <?>
doesn't mean <? extends Long>
...
This is due to capture conversion. Internally, compiler converts the type of an expression Foo<?>
to Foo<X>
, where X
is a specific albeit unknown type.
The compiler is free to infer anything that is compatible with the types of the arguments and return type. In your case it can always infer T
as Object
. Which turns the signature into
static Object wildSub(ArrayList<?> holder, Object arg)
Which means it can take any ArrayList as first argument and anything as second. Since you don't do anything with the return value, Object
will be okay.
If you think about it as the compiler using Object where ? is used, it makes sense why it would compile. That is all there is to it.
If you are doing any operations dependent on ? being a certain class, you will get a cast exception at run time if the wrong class is passed in.
As an addition to existing (correct) answers to make it more clear:
...
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
...
来源:https://stackoverflow.com/questions/7788348/unbounded-wildcard-passed-to-method