super keyword in generics [duplicate] - java

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.

Related

Why is this assignment involving wildcards legal in Java?

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.

Why compare method of Comparator created with wildcard can't accept object?

In Java it is legal to create a comparator object like this:
Comparator<? super Number> comparator = new Comparator<Object>() {
#Override
public int compare(Object o1, Object o2) {
// implementation here
}
};
But you can't use this object for a simple call like this:
Object o1 = new Object(), o2 = new Object();
comparator.compare(o1, o2);
Why so? I thought ? super Number means Number and all its superclasses.
Suppose instead you had used ? super Double:
Comparator<? super Double> comparator = new Comparator<Object>() {
// ...
};
What you are telling the compiler is that you have a Comparator which
might be a Comparator<Double>, or
might be a Comparator<Number>, or
might be a Comparator<Object>, or
might be a Comparator<Serializable>.
Even though you initialized it with a Comparator<Object>, the compiler doesn’t know that, because the compiler doesn’t execute code. The compiler only knows that the variable holds a Comparator of one of the above types.
Since the variable might hold a comparator of a type more specific than Object, the compiler will not assume that it’s okay to pass Object.
Comparator<? super Number> comparator means that comparator refers to something known to be able to accept a Number (or it's null).
A Comparator<Object> can accept a Number; but the compiler doesn't know if the value referred to by a Comparator<? super Number> is a Comparator<Object>, or a Comparator<Number> any more. All it knows is that it's something that can accept a Number, so that's all it will allow you to pass.
Why so? I thought ? super Number means Number and all its superclasses.
No: it means that Number is an acceptable type to pass as a parameter. To put that another way, Number is a subtype of the acceptable parameter type. To put that another way, the acceptable parameter type is a supertype of Number, so it's fine to pass a Number.
See: What is PECS (Producer Extends Consumer Super)?
The reason why o1 and o2 cannot be used as parameters is because they are "more general" than Number and hence they may point to an instance of a class that is part of a different hierarchy starting at some point in parent chain of Number. Something like, Son class is directly in the hierarchical line of Father, but not in the hierarchy of Grandfather class's SecondSon. So, a reference to an instance of Grandfather class cannot be passed since it could be pointing to an instance in its SecondSon's hierarchy.
I have tried to explain a similar point here.

Generics - lower/ upper bound wild card behaviour? [duplicate]

This question already has answers here:
What is PECS (Producer Extends Consumer Super)?
(16 answers)
Closed 5 years ago.
I am trying to understand the behavior of lower as well as upper bound wild cards.
Got an issue while trying to compile the below code.
Collection<? extends Object> c = new ArrayList<Object>();
c.add(new Object()); // Compile time error
For figuring out the issue, I simply tried the lower bound wild card as well. Fortunately or unfortunately, code compiles fine but created so many confusion.
Collection<? super Object> c = new ArrayList<Object>();
c.add(new Object()); // Compiles fine
Can somebody explain me, how these two code snippets are working. It would be great if someone can provide additional examples/links.
Please correct me if I did something wrong above.
Thanks in advance.
? means an "unknown type".
Collection<? extends Object> represents a collection of some type of object. This "some type" can be any type that is a subclass of Object or Object itself. Which type exactly? The compiler does not know.
When you try to add a new Object to the collection, you can't. This is because the collection's type is not known. It can be an ArrayList<String>. It can be a HashSet<Integer>. So the compiler says
"What if the collection is ArrayList<String>? You can't put an Object in there!"
Basically, the compiler is too cautious to let you do that.
Collection<? super Object> represents a collection of some type of object. This "some type" can be any type that is a superclass of Object or Object itself. It can only be one thing here - Object, because Object does not have a superclass. That's why you can add a new Object to the collection.
Even if Object has a superclass, you would still be able to add a new Object(). Let's call the superclass of Object MyClass. Now, the collection can either be a collection of MyClass or Object. Whichever it is, you will be able to add an Object to it.
Let's change the class type to make it a bit more understandable. Your first example changed to Number
Collection<? extends Number> c = new ArrayList<Number>();
Means that there are ? objects from type Number. So it could be anything that extends Number e.g. Integer, Double, Float, BigInteger etc. So you can not guarantee what kind of Number Object resides in the list since
List<Integer> // only allows Integer
List<Double> // only allows Double
List<Float> // only allows Float
That's why you can not add anything to <? extends Number> because it could be either one of the Lists above.
The other way around is for <? super Number>.
This means that every object inside the List is an ancestor of Number. In this case you are allowed to add anything from supertype/type of Number. You guarantee with ? super Number that everything inside is a Number.
But what you can not guarantee is the actual type e.g.
list.get(0); // is a Number, but could be a Integer
list.get(1); // is a Number, but could be a Float
list.get(2); // is a Number, but could be a Double
tl;dr use extends for reading and super for adding.
And here is a graph from the docs https://docs.oracle.com/javase/tutorial/java/generics/subtyping.html
Here is an explanation from Jon Skeet for <? super Number>
https://stackoverflow.com/a/8083260/4467208

unable to understand wildcard generics in this example in Java?

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.

Java Generics (bounded wildcards)

According to the book "Effective Java" of Joshua Bloch there is a rule about how/when use the bounded wildcards in generics. This rule is PECS (Producer-Extends, Comsumer-Super). When I study the following example:
Stack<Number> numberStack = new Stack<Number>();
Iterable<Integer> integers = ... ;
numberStack.pushAll(integers);
I understand that this rule fits perfect in this example. I have to declare the method pushAll as the following sample:
// Wildcard type for parameter that serves as an E producer
public void pushAll(Iterable<? extends E> src) {
for (E e : src)
{
push(e);
}
}
But what happens if I have the following example?
Stack<Integer> integerStack = new Stack<Integer>();
Iterable<Number> numbers = ... ;
integerStack.pushAll(numbers);
I have to declare the pushAll as it follows:
public void pushAll(Iterable<? super E> src) {
for (E e : src)
{
push(e);
}
}
According to PECS rule the above declaration is wrong. But I want to have a Stack of Integers and pass to this Stack a Number. Why not to do it?
Why should I always use the extends keyword? Why using super is wrong?
Of course the same stands for the comsumer's point of view. Why a consumer should always be super?
PS: To be more specific you can find this above example at the sector "Item 28" of the referred book.
When you declare a Stack<Foo> you mean a Stack of Foos, or subclasses of Foo. As an example, you would expect to be able to put a String in a Stack<Object>. The other way is not true, you should not be able to insert another Object, in a Stack<String>.
In your example you declare a Stack<Integer>. You should be able to put Integers in this stack, but not other Numbers (like a Double), which you would if you declared the parameter <? super E>. That's why the put-method should have a paramter of the type <? extends E>.
Trying to store arbitrary numbers in a Stack can't possibly work, since a Number could be something other that an Integer. So your example doesn't make much sense.
You would use super when the object asts as a consumer, i.e. when instances of the generic type of the object are passed as arguments to methods of the object. For example:
Collections.sort(List<T>, Comparator<? super T>)
In this example, the sort method takes T instances from the collection, and passes them as argument to the compare(T o1, T o2) of the comparator.
Contrast this to your first example, where the Iterable src is a producer. The pushAll() method calls a method of the Iterable which roduces (i.e. returns) instances of T. In this case, the iterable is a producer, hence the use of ? extends T
In the pushAll method, you are not passing type E, but any type that extends E. So, instead of passing an Iterable of Numbers, you can pass any Iterable of a type that extends Number.
The original example uses a Number type because you can then pass any type that is a subclass of Number, like Integer, BigDecimal and so on.
In your example, you are doing it the other way around. You are using Integer to declare your Stack. Therefore, pushAll will only be able to accept those classes that are extended by Integer. You will not be able to use Numbers (or any other class, because Integer is a final class).
First thing to notice is that Integer extends Number, so you shouldn't be pushing Number objects into a Stack of Integers. However, the first sample will work with Integers, Floats, BigDecimal and all other Number subclasses.
Your example doesn't make much sense. A construct like <? extends Number> means that Number and every type is allowed which inheits from Number. So you define an upper and a lower boundary, from type Number down to the most specific one. The other way round, <? super Number> means that Number and any of its supertyes are allowed. Since Number extends Object and implements Serializable the following three types are allowed:
java.lang.Number
java.lang.Object
java.io.Serializable
In your example you declare the generic type Stack<Integer>. Let's consider the following.
Your Stack is never be able to hold items of any super type of Integer
Your Stack is never be able to hold items of any subtype of Integer, since Integer class is final and thus it can't be subclassed.
So, if you want to declare the generic type Stack<Integer>, your iterable is of type Iterable<Integer> and thus your Stack can only hold items of type Integer. You are totally right with the mnemonic PECS, but this only works if you have choosen a concrete type which has at least one super type and at least one subtype.

Categories

Resources