Most questions about wildcards want to know why something sensible is rejected by the compiler. My question is the opposite. Why is the following program accepted by the compiler?
void test(List<? extends Number> g1, List<? extends Number> g2)
{
g1 = g2;
}
I tried to explain this from the Java Language Specification, but I have not found the answer. I had the impression from various descriptions of Java generics and wildcards that each use of a wildcard is captured as a completely new type, but apparently not here. I have not found any nasty behavior that follows from this assignment being allowed, but it still seems "wrong".
When I face these questions, I approach this in a slightly different manner.
First of all, every single wildcard is captured, everywhere, by javac. In plain english: every time javac "sees" a wildcard it is going to transform that (this is almost accurate as you will see further). Specifically, let's say we have this:
List<? extends Number> list;
javac will transform to:
List<X1> list
where X1 <: Number, where <: means it is a subtype of, as such : X1 is an unknown type that extends Number. This will happen for every single occurrence. And it might be very weird, at first, in some scenarios:
public static void main(String[] args) {
List<?> l = new ArrayList<String>();
one(l);
two(l, l); // fails
}
public static <T> void one(List<T> single){
}
public static <T> void two(List<T> left, List<T> right){
}
capture conversion was applied individually to each List, it's like this happened:
two(List<X1>, List<X2>)
Now to why is your example accepted, is far more interesting, imho. You know that capture conversion is applied, but according to the JLS it is not applied everywhere:
If the expression name is a variable that appears "on the left hand side", its type is not subject to capture conversion.
It's like saying that only values are capture converted, not variables.
So in this case:
g1 = g2;
g1 has not been capture converted, while g2 has. It's like doing:
List<? extends Number> g1 = List<X1> (g2) // pseudo-code
We know that X1 <: Number so, as such List<X1> is a subtype of List<? extends Number>, so the assignment works.
Even if you change ? extends Number to ? (this is not a bounded wildcard anymore), this would still work.
List<? extends Number> is best read as:
This is a list of numbers, but, covariantly.
In other words, this is a list of some concrete but unknown type. However, I do know that, whatever type it might be, at least it is either Number or some subclass thereof.
Generics is weird; once you opt into some variance, you get the restrictions to go along with that. In the case of collections, 'covariance' comes with the baggage of 'no adding'.
Try it.
g1.add(XXX);
the only thing that is legal for XXX here? null. That's literally it. The full and complete and exhaustive list of all you can add to this thing. certainly Number x = 5; g1.add(x); is not going to be allowed by javac here.
By writing List<? extends a thingie> you're saying: Yeah, I want that. I'm signing up to this restriction that I get to add absolutely nothing (other than the academic case of literal null). In trade for handcuffing yourself, the things you can pass in for g1 is expanded considerably.
You can also opt into contravariance:
void foo(List<? super Integer> list) {
list.add(Integer.valueOf(5)); // works!
Integer x = list.get(0); // no go
}
contravariance is the opposite. add works. get doesn't work. Which in this case means: The type of the expression list.get(0) is just.. Object.
Now that we've covered that:
void test(List<? extends Number> g1, List<? extends Number> g2) {}
means 'my first parameter is a list of numbers, but I opt into covariance handcuffs', and 'my second parameter is a list of numbers, but I also opt into covariance handcuffs for this one too', it now makes sense why java lets you write g1 = g2. g2 is guaranteed to be an X<Y>, where X some concrete subclass of List, and Y is either Number or some subclass thereof.
This is 100% compatible, type-wise, with the notion of 'some sort of list whose type param is some covariant take on Number'. The only thing you can do a List<? extends Number> is to invoke methods of List where any T in the signatures are 'disabled' for parameters, and replaced by the bound (Number) for return types.
That's.. exactly what List<? extends Number> is describing, so it's compatible.
"I had the impression from various descriptions of Java generics and wildcards that each use of a wildcard is captured as a completely new type, "
That statement is correct.
So what? You are confusing the type of the object with the type of the variable.
Consider this code:
String s = "abc";
Object o = s;
o has type Object which is assignment compatible with the type of s. But that doesn't mean String and Object are the same type. No different with your example. You have two different List types for the objects, but one type for the variables. Each variable has type List<? extends Number>, so the assignment is fine. When you make the assignment, the object's generic type is List<x> for some completely new unknown type x. But the variable type remains List<? extends Number>.
How could it not be valid?
Both variables have identical type (in this case List<? extends Number>), so the compiler must allow assignment of one to the other.
The objects assigned to the variables may have different types, but the variable types are identical, so assignment is always legal.
The compiler does not know or care what the actual type of an object assigned to a variable is, even if it can be determined from the code. It cares only about declared types when checking types.
Related
I have a method that is supposed to analyze a String and determine the correct Class<T>, where T extends BaseClass.
Suppose that BaseClass is extended by Child1, Child2 and Child3.
In my method, I want to do something like this:
public <T extends BaseClass> Class<T> from(String number) {
if (number.contains("Child1")) {
return Child1.class;
} else if (number.contains("Child2")) {
return Child2.class;
} else if (number.contains("Child3")) {
return Child3.class;
}
throw new UnsupportedOperationException("Cannot recognize class from " + number);
}
The problem is that the above method doesn't compile on all return statements, because Required type is Class<T>, provided is Class<Child1> (same for Child2 and Child3 of course).
Hence, I am forced to (unchecked) cast:
return (Class<T>) Child1.class;
... which of course works fine, since Child1.class is compatible with Class<T>.
How can I do what I'm trying to do in a cleaner way (without having the warning)?
... which of course works fine, since Child1.class is compatible with Class<T>.
That's incorrect. Understandable, as you're making a common mistake.
The fix
The fix is to have the return type be Class<? extends T> instead. But, scratch that...
But this code is bad style
Generics serve to link things. Any type variable should therefore be declared once and used in at least 2 places, or it is one of:
useless.
actively misleading.
a type-safety breaking hack.
I assume you intended none of that. You have declared T once, and are using it once, which therefore means it's incorrect. The correct version is:
public Class<? extends BaseClass> from(String number) { ... }
This does everything you want. Specifically, something like this:
BaseClass bc = from("Child3").getConstructor().newInstance();
will just compile, no need for casts (you will need to festoon this up with rather a lot of try/catch, but no need for a cast, at least), and the compiler will not emit type safety warnings either. Which, presumably, is what you're trying to accomplish.
Explanation
In java, typing relationships are covariant. That means any type can stand in for any of its supertypes.
In other words:
Number n = Integer.valueOf(5);
is valid java.
But the thing that generics are for simply doesn't adhere to this rule. Here is a trivial example. Imagine generics was just as covariant as basic type usage in java would be. Then I could write this, it would compile, and that would be bad, because this code would then be breaking the typing system:
List<Integer> listOfInts = List.of(1, 2, 3);
List<Number> listOfNums = listOfInts;
listOfNums.add(Double.valueOf(5.5));
int value = listOfInts.get(3);
Go through the above code and you realize there's a fundamental issue here.
The fix is that generics are invariant - a type is a valid standin only for itself; not for anything else.
In other words, the one and only thing you can assign to a List<Number> is an expression of type List<Number> or perhaps ArrayList<Number> ( because the non-generics part is covariant, we're talking only about the stuff in the <>), not List<Integer>.
That's the fix - that's why the above code isn't actually a problem for the typing system in java - it simply won't compile.
Now, when there is no such thing as 'adding', this becomes dubious, and Class is just such a type: Yes it's got a type param but you can't 'break stuff' if generics was covariant. Unfortunately, the generics feature of java does not ship with a gigantic list of 'the generics on THIS type can be covariant, but here they cannot be'.
Instead, java lets you choose your variance, and the APIs change to reflect what that means:
List<? extends Number> list = someListOfIntegers; // co-variance
List<? super Number> list = someListOfObject; // contra-variance
List list = someListOfAnything; // legacy-variance a.k.a. raw
List<Number> list = someListOfNumber; // invariance
Of course, you don't get this stuff for free: That covariant list (List<? extends Number>), you cannot call add on this list, at all. Well, the literal .add(null), because null is a standin for all types, that works, but nothing else will, add is always a compile time error. That's the cost. If you opt out of all add methods on a list, then and only then can you write a method that accepts as parameter a list of numbers, or integers, or doubles, etc.
With Class it gets dubious (as there's no 'writing'), but the co/contra/invariant system is baked into generics and doesn't care about the fact that Class doesn't have any add-style methods in it.
What does List<?> mean, does it mean simply a list of objects of unspecified type?
Googling for the string <?> returns nothing useful (:
As Tom said, the ?, or unbounded wildcard, means that the type of the object is not specified. It could be unknown, could be meant for multiple possible values or might be just plain irrelevant. Your example, List<?>, is pronounced "List of unknown." It's convenient because it's flexible, but there are also some pitfalls because you can't shove random objects in and pull them out of groups of unknown with total impunity.
Resources:
Wildcards are discussed here in the Java tutorial.
There's a good -- if verbose -- tutorial on generics in general by Angelika Langer available here.
And there's another good overview here (PDF) by Gilad Bracha; check out pages 5-7.
Finally, if you can get your hands on Effective Java by Josh Bloch, it's got a great section on generics and the cases in which you can, can't, should and shouldn't use wildcards (chapter 5, pages 109-146 in the second edition).
Incidentally, your Google search failed because Google doesn't truck with special characters:
With some exceptions, punctuation is ignored (that is, you can't search for ##$%^&*()=+[]\ and other special characters).
-Google help page
(EDIT: I must have been really tired when I wrote this last night. Cleaned up formatting/added a little info.)
The keyword you need to get more information is Wildcards
To answer this question I need to explain Unbounded Wildcards and Bounded Wildcards.
The content of this post has been assembled from java documentation.
1. Unbounded Wildcards
The unbounded wildcard type is specified using the wildcard character (?), for example, List<?>. This is called a list of unknown type. There are two scenarios where an unbounded wildcard is a useful approach:
If you are writing a method that can be implemented using functionality provided in the Object class.
When the code is using methods in the generic class that don't depend on the type parameter. For example, List.size or List.clear. In fact, Class<?> is so often used because most of the methods in Class<T> do not depend on T.
2. Bounded Wildcards
Consider a simple drawing application that can draw shapes such as rectangles and circles. To represent these shapes within the program, you could define a class hierarchy such as this:
public abstract class Shape {
public abstract void draw(Canvas c);
}
public class Circle extends Shape {
private int x, y, radius;
public void draw(Canvas c) {
...
}
}
public class Rectangle extends Shape {
private int x, y, width, height;
public void draw(Canvas c) {
...
}
}
These classes can be drawn on a canvas:
public class Canvas {
public void draw(Shape s) {
s.draw(this);
}
}
Any drawing will typically contain a number of shapes. Assuming that they are represented as a list, it would be convenient to have a method in Canvas that draws them all:
public void drawAll(List<Shape> shapes) {
for (Shape s: shapes) {
s.draw(this);
}
}
Now, the type rules say that drawAll() can only be called on lists of exactly Shape: it cannot, for instance, be called on a List<Circle>. That is unfortunate, since all the method does is read shapes from the list, so it could just as well be called on a List<Circle>. What we really want is for the method to accept a list of any kind of shape:
public void drawAll(List shapes) {
...
}
There is a small but very important difference here: we have replaced the type List<Shape> with List<? extends Shape>. Now drawAll() will accept lists of any subclass of Shape, so we can now call it on a List<Circle> if we want.
List<? extends Shape> is an example of a bounded wildcard. The ? stands for an unknown type, however, in this case, we know that this unknown type is in fact a subtype of Shape. (Note: It could be Shape itself, or some subclass; it need not literally extend Shape.) We say that Shape is the upper bound of the wildcard.
Similarly, the syntax ? super T, which is a bounded wildcard, denotes an unknown type that is a supertype of T.
A ArrayedHeap280<? super Integer>, for example, includes ArrayedHeap280<Integer>, ArrayedHeap280<Number>, and ArrayedHeap280<Object>.
As you can see in the java documentation for Integer class, Integer is a subclass of Number that in turn is a subclass of Object.
List: There is no type restriction and assignment restriction at all.
List<Object>: It seems to be used the same as List, but a compilation error will occur when accepting other generic assignments.
List<?>: It is a generic type. Before assignment, it means that it can accept any type of set assignment, but after assignment, you can't add elements to it, but you can remove and clear, not an immutable set. List<?> is generally used as a parameter to receive an external collection, or return a collection of specific element types, also known as a wildcard collection.
The test code and result as followed:
List a1 = new ArrayList();
a1.add(new Object());
a1.add(new Integer(10));
a1.add(new String("string"));
System.out.println("List is : " + a1);
List<?> a4 = a1;
a4.remove(0);
System.out.println("List is : " + a4);
System.out.println("List is : " + a4.get(0));
a4.clear();
System.out.println("List is : " + a4);
The result is :
List is : [java.lang.Object#2a139a55, 10, string]
List is : [10, string]
List is : 10
List is : []
Sounds like you should look for some documentation on Java generics.
The List<?> means that it is an object based on a currently unspecified type. That specification is made when the class is instantiated.
For example:
List<String> listOfStrings = new ArrayList<String>();
is a list of String objects.
List<?> stands for List<? extends Object> so in Collection<E> you will find containsAll(Collection<?> c) which allows you to write
List<Object> objs = Arrays.<Object>asList("one",2,3.14,4);
List<Integer> ints = Arrays.asList(2,4);
assert objs.containsAll(ints);//true
List is an interface you can implement yourself and also implemented by some of the Java collections, like Vector.
You can provide compile-time typing information using the angled brackets. The most generic type would be Object, which would be List<Object>. The <?> you see is indicating a List of some subclass of Object or an Object. This is like saying List<? extends Object>, or List<? extends Foo>, where the List contains objects of some subclass of Foo or objects of Foo itself.
You can't instantiate a List; it's an interface, not an implementation.
When you take an element out of a Collection, you must cast it to the type of element that is stored in the collection. Besides being inconvenient, this is unsafe. The compiler does not check that your cast is the same as the collection's type, so the cast can fail at run time.
Generics provides a way for you to communicate the type of a collection to the compiler, so that it can be checked. Once the compiler knows the element type of the collection, the compiler can check that you have used the collection consistently and can insert the correct casts on values being taken out of the collection.
chk dis pdf
? is nothing but Wildcard in Generics
There are 3 different kind of Wildcards in Generics
1) Upper Bounded Wildcards: Uses extends key word
eg: List<? extends SuperClass>
2) Lower Bounded Wildcards
eg:Uses Super key word List<? super SubClass>
3) Unbounded Wildcard
List<?> list
List<?> is equivalent to List<? extends Object>
The wildcard ? extends Object is equivalent to the unbounded wildcard ?
<?> in java specification
Generics in java specification
You are probably looking at the template based List class. You can create a list of strings by List<String> myList = new MyList<String>(); as an example. Check the documentation for all the types it supports. It should support any object type, but if there is a sort functionality you have to supply some compare functions.
Note that in the example above MyList is a concrete class that implements the List interface in Java. It can be ArrayList.
EDIT:
I assumed List as a concrete class by mistake. Fixed the error above. Thanks Jon.
I went through these topics
Generics..? Super T
Bounding generics with 'super' keyword
However, I still seem to be kind of lost with super keyword:
When we declare a collection like that:
List<? super Number> list = null;
list.add(new Integer(0)); // this compiles
list.add(new Object()); // this doesn't compile
shouldn't it be the opposite - we have a list that contains some objects (of unknown type) which are parents of Number. So Object should fit (since it is the parent of Number), and Integer shouldn't. The opposite is the case for some reason.
Provided we have the following code
static void test(List<? super Number> param) {
param.add(new Integer(2));
}
public static void main(String[] args) {
List<String> sList = new ArrayList<String>();
test(sList); // will never compile, however...
}
It is impossible to compile the above code (and my sanity suggests that this is the right behaviour), but the basic logic could prove the opposite:
String is Object, Object is superclass of Number. So String should work.
I know this is crazy but isn't this the reason why they didn't allow <S super T> constructs? If yes, then why <? super T> is allowed?
Could someone help me restore the missing part of this logic chain?
The bounded wildcard in List<? super Number> can capture Number and any of its supertypes. Since Number extends Object implements Serializable, this means that the only types that are currently capture-convertible by List<? super Number> are:
List<Number>
List<Object>
List<Serializable>
Note that you can add(Integer.valueOf(0)) to any of the above types. however, you CAN'T add(new Object()) to a List<Number> or a List<Serializable>, since that violates the generic type safety rule.
Hence it is NOT true that you can add any supertype of Number to a List<? super Number>; that's simply not how bounded wildcard and capture conversion work. You don't declare a List<? super Number> because you may want to add an Object to it (you can't!); you do because you want to add Number objects to it (i.e. it's a "consumer" of Number), and simply a List<Number> is too restrictive.
References
Angelika Langer's Generics FAQs
What is a bounded wildcard?
When would I use a wildcard parameterized type with a lower bound? ("When a concrete parameterized type would be too restrictive.")
Why is there no lower bound for type parameters? ("Because it does not make sense.")
JLS 5.1.10 Capture Conversion
See also
Effective Java 2nd Edition, Item 28: Use bounded wildcards to increase API flexibility
"PECS stands for producer-extends, consumer-super
Related questions
Too many to list, PECS, new Integer(0) vs valueOf, etc
For the first part List<Number> fits in List<? super Number> but you can't add an Object to a List<Number>. That's why you can't add an Object to List<? super Number>.
On the other hand you can add every subclass of Number (Number included) to your list.
For the second part, String is an Object, but String isn't a superclass of Number.
If it worked like this, as every class is a subclass of Object, super would have no meaning.
Let's see every possible cases with List<? super Number> :
The passed list is a List<Object>
List<Object> will work
Object fits in <? super Number>
You can add any subtype of Number to a List<Object>
Even if you could also add String in it the only thing you're sure of is that you can add any subclass of Number.
The passed list is a List<Number> :
List<Number> will work
Number fits in <? super Number>
You can add any subtype of Number to a List<Number>
The passed list is a List<Integer> (or any subclass of Number):
List<Integer> won't work
Integer is a subclass of Number so it is exactly what we want to avoid
Even if an Integer fits in a Number you wouldn't be abble to add any subclass of Number in a List<Integer> (for example a Float)
super doesn't mean a subclass.
The passed list is a List<String> (or any class not extending Number nor in the "super hierarchy" of Number (ie. Number and Object) :
List<String> won't work
String doesn't fit in Number "super hierarchy"
Even if String fits in Object (which is a super class of Number) you woudln't be sure to be able to add a Number to a List that contain any subclass from one of the super classes of Number)
super doesn't mean any subclass of one of the super classes, it only means one of the super classes.
How does it work ?
You could say that as long as you can add any subclass of Number with your typed List, it respects the super keyword.
I didn't get it for a while. Many of the answers here, and the other questions show specifically when and where certain usages are errors, but not so much why.
This is how I finally got it. If I have a function that adds Numbers to a List, I might want to add them of type MySuperEfficientNumber which is my own custom class that implements Number (but is not a subclass of Integer). Now the caller might not know anything about MySuperEfficientNumber, but as long as they know to treat the elements added to the list as nothing more specific than Number, they'll be fine.
If I declared my method as:
public static void addNumbersToList(List<? extends Number> numbers)
Then the caller could pass in a List<Integer>. If my method added a MySuperEfficientNumber to the end of numbers, then the caller would no longer have a List of Integers and the following code wouldn't work:
List<Integer> numbers = new ArrayList<Integer>();
addNumbersToList(numbers);
// The following would return a MySuperEfficientNumber not an Integer
Integer i = numbers.get(numbers.size()-1)
Obviously this can't work. And the error would be inside the addNumbersToList method. You'd get something like:
The method add... is not applicable for the arguments (MySuperEfficientNumber)
Because numbers could be any specific kind of Number, not necessarily something that MySuperEfficientNumber is compatible with. If I flipped the declaration around to use super, the method would compile without error, but the caller's code would fail with:
The method addNumbersToList(List<? super Number>)... is not applicable for the arguments (List<Integer>)
Because my method is saying, "Don't think that your List can be of anything more specific than Number. I might add all sorts of weird Numbers to the list, you'll just have to deal with it. If you want to think of them as something even more general than Number -- like Object -- that's fine, I guarantee they'll be at least Numbers, but you can treat them more generally if you want."
Whereas extends is saying, "I don't really care what kind of List you give me, as long as each element is at least a Number. It can be any kind of Number, even your own weird, custom, made-up Numbers. As long as they implement that interface, we're good. I'm not going to be adding anything to your list since I don't know what actual concrete type you're using there."
List<? super Number> means that the reference type of the variable suggests we have a list of Numbers, Objects or Serializables.
The reason you can't add an Object, is because the compiler does not know WHICH of these classes are in the generic definition of the actual instantiated object, so it only allows you to pass Number or subtypes of Number, like Double, Integer and so on.
Let's say we have a method that returns a List<? super Number>. The creation of the object inside the method is encapsulated from our view, we just can't say if it is something like this:
List<? super Number> returnValue = new LinkedList<Object>();
or
List<? super Number> returnValue = new ArrayList<Number>();
So, the generic type could be Object or Number. In both cases, we would be allowed to add Number, but only in one case we would be allowed to add Object.
You have to distinguish between the reference type and the actual object type in this situation.
There are two angles here: what you can put into a collection and what you can get from a collection, when bounded types are involved.
Let's look at the ? extends Number case first. When a collection with such bounds is defined, what we know is that : every element will have an upper bound as Number. We don't know the exact type (might be an Integer/Long/etc), but we do know, for sure, that its upper bound is Number.
So reading from such a collection gets us a Number. This is the only guaranteed type we can get from it.
Writing to such a collection is prohibited. But why? Didn't I say that while we read - we will always get a Number, so why prohibit writing to it? The situation is slightly more involved here:
List<Integer> ints = ....;
List<? extends Number> numbers = ints;
numbers.add(12D); // add a double in here
If addition would have been allowed into numbers, you could have effectively added a Double in a List of Integers.
Now to your example:
List<? super Number> list = null;
list.add(new Integer(0));
list.add(new Object());
We know about list that it contains a certain supertype of Number, for example Object.
Reading from such a list would get us a certain type X, where X would be a parent of Number. So what would that be? You can't really know. It could be a theoretical MyNumber extends Number, or much simpler: an Object. Since you can't know for sure, the only safe thing to read from that would be the super-type of everything - Object.
What is a bit weird may be :
List<? super String> list = ...;
String s = list.get(0); // fails, compiler does not care that String is final
Writing to it is slightly more complicated, but only slightly. Remember what we know is inside that list: it's a type that Number extends/implements (if it were an interface), so you can always assign a subtype (or Number itself) to that supertype.
Some type X
/ \
|
Number
/ \
|
Some type Y that we an put in here
List<? super Number> is such a List<AncestorOfNumber> where we can implicitely cast each Number to its super type AncestorOfNumber.
Consider this: What generic type needs to be ???? in the following example?
InputStream mystream = ...;
void addTo(List<????> lsb) {
lsb.add(new BufferedInputStream(mystream));
}
List<BufferedInputStream> lb = new ArrayList<>();
List<InputStream> li = new ArrayList<>();
List<Object> lo = new ArrayList<>();
...
{ addTo(lb); addTo(li); addTo(lo); }
The answer: ???? is anything to which we can cast BufferedInputStream, which is that very same or one of its ancestors: ? super BufferedInputStream
May I give a very simple Example.
public void add(List<? super Number> list) {
}
this will allow these calls
add(new LinkedList<Number>());
and everything above Number like
add(new LinkedList<Object>());
but nothing below the hierarchy so not
add(new LinkedList<Double>());
or
add(new LinkedList<Integer>());
So since its not clear for the program to know whether you give a List with Number or Object the compiler cannot allow you to add anything above Number to it.
For example a List would not accept an Object in spite of Object who would accept a Number. But since this is not clear the only valid input would be Number and its sub types.
while reading through this article I got stuck here. I am pasting this from the link. I do not understand the reasoning given for why List<Number> or List<? extends Number> cannot be used here.
public void doStuff( List<Integer> list ) {
list.add(1);
// do stuff
list.get(0);
}
We can generalize this one step further by generalizing the generic parameter:
public void doStuff( List<? super Integer> list ) {
list.add(1);
// do stuff
list.get(0);
}
Some readers might ask why the more intuitively List<Number> can’t be used here. Indeed, we
could try to define the method as taking a List<Number> or a List<? extends Number>, but the first
definition would exclude the possibility for passing in an actual ArrayList<Integer>, while the
second definition would disallow the add() method (as someone may otherwise be passing an
ArrayList<Float> in, and would find an Integer to be between the Floats after the call to doStuff).
In normal Java, yes, an Integer is a Number. But in generics, List<Integer> is not a List<Number>.
To see why, attempt to assign a List<Integer> to a List<Number> and see what happens:
List<Number> numberList = new ArrayList<Integer>(); // not allowed
// This would have been allowed, even though the argument is
// boxed to a `Double`, not a `Integer`.
numberList.add(8.6);
But what about <? extends Number>? Wouldn't that cover a List<Integer>? Yes, but the references loses information about the exact type of Number. What if that was the case?
List<? extends Number> numberList = new ArrayList<Integer>(); // allowed
numberList.add(8.6); // disallowed
The reason is that the List<? extends Number> could be of anything that extends Number, such as List<BigDecimal>. So it must disallow calling the add method (or any method in that class with the generic type parameter as a parameter to that method) (except for null) to maintain type safety.
Java is perhaps a bit confusing because there is a bit of a double standard at work.
First you must consider that both arrays and collections are reference types, i.e. their instances are objects whose data is allocated to heap memory and indicated by a reference pointer.
Both arrays and collections therefore have two types at work: the type of object itself as well as the types of each of the components in the array or collection. To make this concrete, here is an example:
String[] strings = new String[] { "AA", "BB", "CC" };
The type of the object that is created is String[] and the types of all the components is String.
Arrays are covariant which allows the JVM to cast both the object type and the component type together. This is why assignments like this are valid:
Object[] objects = strings;
For arrays, because Object is a supertype of String, then Object[] is also a supertype of String[]. Arrays are covariant.
This does NOT apply to reference types that are not arrays, eg. Collections. Collections are invariant. Therefore, even though a Integer is a subtype of Number, collections are invariant and so List<Integer> is NOT a subtype of List<Number>.
For the first case, accepting a List<Number> only allows a List (ArrayList, LinkedList, ...) of Number elements, not a List of any other type (including Integer). The list has to be specifically typed in the calling function as List<Number> (or ArrayList<Number>, or LinkedList<Number>, or ...). In other words, the type of list is flexible but the generic argument is not.
In the second case, use the "is a" wording and it makes sense. An Integer "is a" Number, but the reverse is not always true. Since the code in the example is assuming all values in use within the function are integers, it must put a limit on the generic that prevents anything less specific than Integer from being passed in.
We need to examinate two things:
What does the wildcard mean in the signature void doStuff(Foo<? super Bar> foo)
What does the wildcard mean inside the method body
Java has only one very simple rule to decide the subtype relation between Foo<A> and Foo<B>: none is a subtype of the other. We say that generic types are invariant, and even if there's a rationale because the Java designers made it this way, from your point of view it's an arbitrary decision.
It's the angle brackets that confuse us, poor developers: we have no problem in accepting that FooBar and FooQoo are not related in any way; but for some reason we need to believe that Foo<Qoo> and Foo<Bar> are. No, that's not the case.
No matter how A and B relate to each other, X<A> and X<B> are not
related.
No matter how A and B relate to each other, X<A> and X<B>
are not related.
No matter how A and B relate to each other, X<A>
and X<B> are not related.
Once you are convinced of the above, please observe this snippet:
List<Double> doubles = ...;
List<Integer> integers = ...;
Number firstDouble = doubles.get(0);
Number firstInteger = integers.get(0);
Calling get(0) on both lists gives us a Number-compatible object. We may want to put the call to get() in a method like getFirstOfList(list) but we just learned that such a method can't exist, because it would accept two totally unrelated types.
This is where wildcards come into play! We observe that calling get() on a List<Number>, a List<Integer>, a List<Double> (and so on) return a Number-compatible object (ie Number or a subtype of it), so there must be a way to express this at the language level. The Java designers gave us the wildcard, which works like this: when you declare
public void doStuff(List<? extends Number> arg);
it has the same effect as declaring the following infinite list:
public void doStuff(List<Number> arg);
public void doStuff(List<Integer> arg);
public void doStuff(List<Double> arg);
public void doStuff(List<Float> arg);
public void doStuff(List<BigDecimal> arg);
...
Without the device of the wildcard you'd have to write one method for each supported list type (which btw is illegal in Java, but that's another story).
The wildcard I used in my example has an upper bound, identified by the extends keyword. The snippet you pasted, instead, adopts a lower bounded wildcard in the method signature (super). Actually it may contain some errors because for example:
you can't pass a List<Integer> to doStuff()
you can only get an Object from list.get(index)
so I will just tell you that the signature
void doStuff(List<? super Number> arg);
stands for the finite list:
void doStuff(List<Number> arg);
void doStuff(List<Object> arg);
and you can put any Number you like in a List<? super Number> but you'll only get() Object's from it.
why are these declaration invalid in Java?
List<Number> test = new ArrayList<? extends Number>();
List test = new ArrayList<? extends Number>();
are we not allowed to use wildcard during instantiation. and if the wildcards are only useful for passing them to methods?
and List<Object> test = new ArrayList<Integer>(); is illegal because generics are not covariant correct?
The ? wildcard character means "unknown" not "any". It doesn't make any sense to instantiate a new container of unknown contents, what would you put in there? It can't really be used for anything!
So the declaraion new ArrayList<? extends Number>() Means "some specific thing that extends number, but I don't know what." It does not mean "anything that extends number."
The List<Number> you assigned it to would allow both Double and Integer to be added to it, but the actual contents of a List<? extends Number> might be Float! (or whatever else.)
Consider what would happen in this code if the wildcard worked as an "Any":
List<Integer> listInteger = new ArrayList<Integer>();
listInteger.add(Integer.valueOf(1));
List<? extends Number> listWildCard = listInteger;
listWildCard.add(Double.valueOf(1.0)); //This does not compile
Integer integer = listInteger.get(1);//because this would throw a ClassCastException
Footnote regarding your second example:
Declaring a paramaterized type with no type parameter is called using the Raw Type. This is considered a programming error. The syntax is only legal so that code written before java 5 still compiles. Just don't do it if your scenario isn't backward compatability with pre-java 5.
To understand why it is not allowed to create objects of wildcard parameterized types, you must first understand what's the use of wildcard parameterized types.
Why wildcards?
As you already know that Java generics are invariant. So a List<Number> is not a super class of List<Integer>, even though their type arguments are covariant. So, what if you want such a behaviour in generics too, like having the same reference pointing to different objects? That polymorphic thing, as you would name it. What if you want a single List reference to refer to list of Integer, Float, or Double?
Wildcards to the rescue:
With wildcards, you can achieve the above mentioned behaviour. So, a List<? extends Number> can refer to a List<Integer>, List<Double>, etc. So, the following declarations are valid:
List<? extends Number> numbers = new ArrayList<Integer>();
numbers = new ArrayList<Double>();
numbers = new ArrayList<Float>();
numbers = new ArrayList<String>(); // This is still not valid (you know why)
So what did we change here? Just the reference type of the numbers. Note that generics were introduced in Java for enforcing stronger compile time check. So, it's primarily the compiler's job to decide whether the declaration of a parameterized type is conforming to the rule or not. Without wildcard, compiler shows you error for a List<Number> refering to List<Integer>.
So, wildcards are just a way to introduce co-variance like behaviour into generics. By using wildcards, you increase the flexibility, or you can say, reduce the restriction that compiler enforces. A List<? extends Number> reference tells the compiler that the list can refer to a list of Number or any subtype of Number(Of course, there are lower bounded wildcards too. But that's not the point here. The differences between them is already discussed in many other answers on SO only).
Major uses of wildcard parameterized type you would see with method parameters, where you want to pass different instantiation of a generic type for a single method parameter:
// Compiler sees that this method can take List of any subtype of Number
public void print(List<? extends Number> numbers) {
// print numbers
}
But at runtime, for creating an object you have to give a concrete type. A wildcard - bounded, or unbounded, is not a concrete type. ? extends Number could mean anything that is subtype of Number. So what type of List would you expect to be created when you create a List<? extends Number>?
You can consider this case similar to the reason why you can't instantiate an interface. Because they aren't just concrete.
There is a workaround. Really?
Although this is illegal, you would be surprised to know that there is a workaround, as explained in - Java Generics FAQs. But I really don't think you would ever need that.
When you instantiate a parameterized class, the parameter has to be some known, concrete type. It can be parameterized class even with ? but for inference reasons it has to be concrete. E.g. this is a valid declaration: new ArrayList<List<?>>();
The trick here is that the methods that use the type parameter in the arguments of their signature require the type of the argument to be lower bound. That is, any parameter that you pass in can be cast to the parameter type. Example:
public void fillUp(List<? super T> param)
The fillUp method takes a collection and fills it with T type objects. The param list must be able to handle the T objects so it is declared that the list can contain types that are ancestors of T, T can be safely cast to that type. If T was not a concrete type, like ? extends Number, then it would be impossible to exactly define all ancestors of T.
That's not a valid declaration as it's not a known type. You're not specifying a full type here. new ArrayList<Number> can accept anything that extends Number by subtyping so your use of ? extends Foo is not a valid need.
List<Number> can accept Integer, Long, etc. There's no way to do the equivalent of ? super Foo as it would be semantically meaningless beyond List or List<Object> with a strange artificial restriction.
Your current definition is not true, The generic type should be same in both sides or should be have inheritance relation.
Java generics are not covariant. See, for example, the article Java theory and practice: Generics gotchas by Brian Goetz. Your first example has two problems. First, when you instantiate a type it must be fully specified (including any type parameters). Second, the type parameters must exactly match the left side.
Regarding type covariance (or lack thereof), this is also not legal:
List<Number> test = new ArrayList<Integer>();
despite the fact that Integer extends Number. This also explains why the second example is illegal. A raw type is more or less the same as binding the type parameter to Object, so it would be like:
List<Object> test = new ArrayList<Integer>();
which again fails because generics are not covariant.
As to why the type parameters must be fully specified, the Java Language Specification, §8.1.2 explains the concept:
A generic class declaration defines a set of parameterized types (§4.5), one for each possible invocation of the type parameter section by type arguments.
You can only instantiate an actual type. As long as a type parameter of a generic type is unbound, the generic type itself is incomplete. You need to tell the compiler which specific parameterized type (among the set defined by the generic class) is being instantiated.
As to why generics are not covariant, this was intended to prevent the following sorts of errors:
List<Integer> iTest = new ArrayList<Integer>();
List<Number> test = iTest;
test.add(Double.valueOf(2.5));
Integer foo = iTest.get(0); // Oops!
Do not get confused by the Java inheritance concept and wildcard (e.g. ? here) syntex of Java generic concept. Both are not the same and none of the inheritance rule applies to java generic concept.
Hence Number is not same as ? extends Number
Please note that Java Generic wildcard is intended to tell the compiler about the intended object use. At runtime, it does not exist at all!
If you see generic in java just as a tool to prevent you to make mistakes, you should not go wrong in understanding this concept.