Difference between ? super T and ? extends T in Java
extends
The wildcard declaration of List<? extends Number> foo3
means that any of these are legal assignments:
List<? extends Number> foo3 = new ArrayList<Number>(); // Number "extends" Number (in this context)
List<? extends Number> foo3 = new ArrayList<Integer>(); // Integer extends Number
List<? extends Number> foo3 = new ArrayList<Double>(); // Double extends Number
Reading - Given the above possible assignments, what type of object are you guaranteed to read from
List foo3
:- You can read a
Number
because any of the lists that could be assigned tofoo3
contain aNumber
or a subclass ofNumber
. - You can't read an
Integer
becausefoo3
could be pointing at aList<Double>
. - You can't read a
Double
becausefoo3
could be pointing at aList<Integer>
.
- You can read a
Writing - Given the above possible assignments, what type of object could you add to
List foo3
that would be legal for all the above possibleArrayList
assignments:- You can't add an
Integer
becausefoo3
could be pointing at aList<Double>
. - You can't add a
Double
becausefoo3
could be pointing at aList<Integer>
. - You can't add a
Number
becausefoo3
could be pointing at aList<Integer>
.
- You can't add an
You can't add any object to List<? extends T>
because you can't guarantee what kind of List
it is really pointing to, so you can't guarantee that the object is allowed in that List
. The only "guarantee" is that you can only read from it and you'll get a T
or subclass of T
.
super
Now consider List <? super T>
.
The wildcard declaration of List<? super Integer> foo3
means that any of these are legal assignments:
List<? super Integer> foo3 = new ArrayList<Integer>(); // Integer is a "superclass" of Integer (in this context)
List<? super Integer> foo3 = new ArrayList<Number>(); // Number is a superclass of Integer
List<? super Integer> foo3 = new ArrayList<Object>(); // Object is a superclass of Integer
Reading - Given the above possible assignments, what type of object are you guaranteed to receive when you read from
List foo3
:- You aren't guaranteed an
Integer
becausefoo3
could be pointing at aList<Number>
orList<Object>
. - You aren't guaranteed a
Number
becausefoo3
could be pointing at aList<Object>
. - The only guarantee is that you will get an instance of an
Object
or subclass ofObject
(but you don't know what subclass).
- You aren't guaranteed an
Writing - Given the above possible assignments, what type of object could you add to
List foo3
that would be legal for all the above possibleArrayList
assignments:- You can add an
Integer
because anInteger
is allowed in any of above lists. - You can add an instance of a subclass of
Integer
because an instance of a subclass ofInteger
is allowed in any of the above lists. - You can't add a
Double
becausefoo3
could be pointing at anArrayList<Integer>
. - You can't add a
Number
becausefoo3
could be pointing at anArrayList<Integer>
. - You can't add an
Object
becausefoo3
could be pointing at anArrayList<Integer>
.
- You can add an
PECS
Remember PECS: "Producer Extends, Consumer Super".
"Producer Extends" - If you need a
List
to produceT
values (you want to readT
s from the list), you need to declare it with? extends T
, e.g.List<? extends Integer>
. But you cannot add to this list."Consumer Super" - If you need a
List
to consumeT
values (you want to writeT
s into the list), you need to declare it with? super T
, e.g.List<? super Integer>
. But there are no guarantees what type of object you may read from this list.If you need to both read from and write to a list, you need to declare it exactly with no wildcards, e.g.
List<Integer>
.
Example
Note this example from the Java Generics FAQ. Note how the source list src
(the producing list) uses extends
, and the destination list dest
(the consuming list) uses super
:
public class Collections {
public static <T> void copy(List<? super T> dest, List<? extends T> src) {
for (int i = 0; i < src.size(); i++)
dest.set(i, src.get(i));
}
}
Also see
How can I add to List<? extends Number> data structures?
What is the difference between 'super' and 'extends' in Java Generics
See Effective Java 2nd Edition, Item 28:
PECS
Producer extends, Consumer super
If your parameter is a producer, it should be <? extends T>
, if it's a consumer it has to be <? super T>
.
Take a look at the Google Collections, they know how to use it, because they got Bloch ;)
What is a difference between ? super E and ? extends E?
The first (<? super E>
) says that it's "some type which is an ancestor (superclass) of E"; the second (<? extends E>
) says that it's "some type which is a subclass of E". (In both cases E itself is okay.)
So the constructor uses the ? extends E
form so it guarantees that when it fetches values from the collection, they will all be E or some subclass (i.e. it's compatible). The drainTo
method is trying to put values into the collection, so the collection has to have an element type of E
or a superclass.
As an example, suppose you have a class hierarchy like this:
Parent extends Object
Child extends Parent
and a LinkedBlockingQueue<Parent>
. You can construct this passing in a List<Child>
which will copy all the elements safely, because every Child
is a parent. You couldn't pass in a List<Object>
because some elements might not be compatible with Parent
.
Likewise you can drain that queue into a List<Object>
because every Parent
is an Object
... but you couldn't drain it into a List<Child>
because the List<Child>
expects all its elements to be compatible with Child
.
Why super keyword in generics is not allowed at class level
Quoting Java Generics: extends, super and wildcards explained:
The super bound is not allowed in class definition.
//this code does not compile !
class Forbidden<X super Vehicle> { }Why? Because such construction doesn't make sense. For example, you can't erase the type parameter with Vehicle because the class Forbidden could be instantiated with Object. So you have to erase type parameters to Object anyway. If think about class Forbidden, it can take any value in place of X, not only superclasses of Vehicle. There's no point in using super bound, it wouldn't get us anything. Thus it is not allowed.
What is ? super T syntax?
super in Generics is the opposite of extends. Instead of saying the comparable's generic type has to be a subclass of T, it is saying it has to be a superclass of T. The distinction is important because extends tells you what you can get out of a class (you get at least this, perhaps a subclass). super tells you what you can put into the class (at most this, perhaps a superclass).
In this specific case, what it is saying is that the type has to implement comparable of itself or its superclass. So consider java.util.Date. It implements Comparable<Date>
. But what about java.sql.Date? It implements Comparable<java.util.Date>
as well.
Without the super signature, SortedList would not be able accept the type of java.sql.Date, because it doesn't implement a Comparable of itself, but rather of a super class of itself.
Use of '? extends ' and '? super ' in Collection generics
The wildcards introduce restrictions in how the collection can be used.
For example, with List<? extends Number>
, I can't add new elements to the list. This is because all I know is that the list is some kind of subtype of Number
, but I don't know what that actual subtype is (so how could I know what to add?). For example, take the following code:
public void doSomethingWith(List<? extends Number> numbers) {
numbers.add(Integer.valueOf(0)); // Won't compile
}
This won't compile because both of these method calls are legal:
doSomethingWith(new ArrayList<Integer>());
doSomethingWith(new ArrayList<Double>());
What you can do is read elements from the list:
// This will all compile
public void doSomethingWith(List<? extends Number> numbers) {
for (Number number : numbers) {
// Do something with number
}
// OR
Number number = numbers.get(0);
// OR
Number number = numbers.remove(0);
}
Calls to methods like get
will return some kind of Number
, we know that for a fact because of the ? extends Number
, so we can treat it like that for reading purposes.
On the other hand, List<? super Integer>
has exactly the opposite result. I can no longer read from the list, but I can write to it. I know that whatever ?
is, it will definitely be a super-class of Integer
, so concrete types of the list will definitely accept Integer
values. For example:
public void doSomethingWith(List<? super Integer> integers) {
integers.add(Integer.valueOf(0));
}
That code is completely legal. However, if you want to read from the list, the only way to do this is to use Object
since anything else requires casting (which requires knowing its concrete type):
for (Object obj : integers)
// OR
Object obj = integers.get(0);
// OR
Object obj = integers.remove(0);
What's Really Happening
Here's what's actually happening. When you specify ? extends Number
, you're making any method that takes elements as a parameter unusable. In fact, if you try to auto-complete code in Eclipse using Ctrl+Space on a List<? extends Number>
, it shows null
as the parameters' types in the add
methods and the like. Meanwhile, all the methods that return elements are guaranteed to return at least some kind of Number
, though you won't know exactly which subclass of Number
it might actually be.
When you specify ? super Integer
, you're making any method that takes elements as a parameter guarantee that they'll accept Integer
values (and sub-classes of Integer
as well). This allows you to call methods like add
since you know they'll accept Integer
types. Meanwhile, all methods that return elements are only guaranteed to return something, but we don't know what, so all the methods that return elements are only guaranteed to return Object
.
PECS is an excellent acronym to remember this, it means "Producer Extends, Consumer Supers". This means that if you want your list to give you something, it's a producer, and you should use extends
. If you want your list to accept things from you, it's a consumer, so you use super
. See this answer for more.
But what if I have a wildcard with no bounds?
It does both! <?>
restricts you from calling methods that take the generic type as an argument and causes all the methods that return the generic type to return Object
. This is because we have no idea what the type is whatsoever. For example, all of these assignments into a List<?>
are legal:
List<?> list;
list = new ArrayList<Integer>();
list = new ArrayList<String>();
list = new ArrayList<MyClass>();
And so on.
Generics super vs. extends
Your first declaration
Organic<? extends Organic> compound
means that compound
could be an Organic<SomeSubtypeOfHexane>
(since Aliphatic
extends Organic
, Hexane
extends Aliphatic
and SomeSubtypeOfHexane
extends Hexane
).
In that case, compound.react(new Organic())
, compound.react(new Aliphatic())
and compound.react(new Hexane())
would lead to a type error, since E
in compound
must be a SomeSubtypeOfHexane
(or subtype thereof).
Your second declaration
Organic<? super Aliphatic> compound
means that compount
could be an Organic<Aliphatic>
.
In that case compound.react(new Organic())
would lead to a type error, since E
must be an Aliphatic
(or subtype thereof).
Remember that declaring a variable using A<? extends B>
or A<? super B>
- extends the amount of objects that can be assigned to it, and, in consequence,
- restricts what can be done with the variable.
Since the exact type of the class is unknown (only a constraint is known), the compiler has to err on the side of safety and disallow certain operations that are either not co- or contravariant. (If you are not already familiar with it, Co- and contravariance is the scientific background of these types of generics.)
super and extends combined for generics in Java
No, Java does not let you simultaneously specify both bounds. That said, I've never run across a situation where both bounds were needed. There's almost no reason to include some subclasses but not others - if you need to exclude subclasses, those subclasses are probably violating their contract.
Related Topics
Java Sax Parser Split Calls to Characters()
How Does Java's Preparedstatement Work
Gson Custom Seralizer for One Variable (Of Many) in an Object Using Typeadapter
Explicit Type Casting Example in Java
Spring Qualifier and Property Placeholder
How to Solve the 'Classic' Knapsack Algorithm Recursively
How to Handle Print Dialog in Selenium
Java - Removing Duplicates in an Arraylist
How to Read Request Body Multiple Times in Spring 'Handlermethodargumentresolver'
Populate Jtable with Large Number of Rows
Programmatically Change Log Level in Log4J2
Mockito: Invaliduseofmatchersexception
Exclude @Component from @Componentscan
Jsoup Character Encoding Issue
Using Enums While Parsing JSON with Gson
Handling Java Crypto Exceptions
In Java, How to Get the Difference in Seconds Between 2 Dates