Reputation: 2532
Why is the following legal when String & Integer are not super classes of Object ?
List<? super Object> mylist = new ArrayList<Object>();
mylist.add("Java"); // no compile error
mylist.add(2);
I'm aware that wild card guidelines use lower bounded wild cards and super for 'out' variables but it seems that Object doesn't function as a 'lower bound' in this case.
Also is this the only way to allow addition of any type into a list ?
Upvotes: 4
Views: 175
Reputation: 122519
It's really simple. Remember that in Java, an instance of a subtype is also an instance of its supertypes.
Look at the signature of add
public boolean add(E e)
That means whatever you pass something whose type is E
or any subtype of E
.
You have a List<? super Object>
. So you can pass to myList.add()
anything whose type is ? super Object
(an unknown type which could be Object
or supertype thereof) or any subtype thereof.
Is Integer a subtype of all types contained by ? super Object
? Of course. Integer
is a subtype of Object
, which is a subtype of all types contained by ? super Object
(of course, in this case, only Object
satisfies this).
You're confusing the type parameter with the things you can pass to methods. The type argument of List<? super Object>
is an unknown type that is a supertype of Object
, so Integer
or String
cannot be the actual type parameter. In fact, in this case the only valid actual type argument would be Object
. But what you're asking when you pass something to the method is, is the thing I'm passing a subtype? And the answer is yes.
Upvotes: 4
Reputation: 10055
It's because Object is a superclass for Integer and String. You're interpreting the generic relationship the other way around.
Edit
Think about this situation:
List<? extends myClass> listOfMyClass = new ArrayList<Object>();
In this case, you'll end up with a list of Object
type elements but that have to respect the restriction added by the declaration of the listOfMyClass
list.
You'll be able to add any object that belongs to the myClass
hierarchy to the list. The ArrayList
that's implementing the List
interface will hold (and return) Object
type elements when requested.
Of course, you can define this:
List<? extends myClass> listOfMyClass = new ArrayList<mySuperClass>();
As you might now, the ArrayList
must contain objects with the same type or a supertype of myClass
and, in this case, that's the mySuperClass
. This list will return mySuperClass
objects qhen requested.
Taking ClassX
as a class that does not belong to the mySuperClass hierarchy, the following line won't compile:
List<? extends myClass> listOfMyClass = new ArrayList<ClassX>();
That's because ClassX
is not a superclass of myClass
.
Upvotes: 3
Reputation: 27579
I agree that it's confusing, but here's what's happening.
In this line of code:
List<? super Object> mylist...
You're saying that myList
is a List
, where each element can be of a type that is Object
or a superclass of Object
. However, you're only declaring the type of myList
here.
What the wildcard does is restricts your implementation of myList
.
Then, you do this:
List<? super Object> mylist = new ArrayList<Object>();
Now what you're doing is instantiating an ArrayList<Object>
. Your lower bound wildcard is used to check that this is valid. It is valid, because Object
matches ? super Object
. At this point, you have a List<Object>
and your ensuing method calls are permitted.
Upvotes: 3