Reputation: 82
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>
...
Upvotes: 3
Views: 185
Reputation: 45433
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.
Upvotes: 1
Reputation: 2759
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
...
Upvotes: 1
Reputation: 122439
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.
Upvotes: 3
Reputation: 1565
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.
Upvotes: 2