Java generics super keyword
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
- "PECS stands for producer-
Related questions
- Too many to list, PECS,
new Integer(0)
vsvalueOf
, etc
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.
Bounding generics with 'super' keyword
super
to bound a named type parameter (e.g. <S super T>
) as opposed to a wildcard (e.g. <? super T>
) is ILLEGAL simply because even if it's allowed, it wouldn't do what you'd hoped it would do, because since Object
is the ultimate super
of all reference types, and everything is an Object
, in effect there is no bound.
In your specific example, since any array of reference type is an Object[]
(by Java array covariance), it can therefore be used as an argument to <S super T> S[] toArray(S[] a)
(if such bound is legal) at compile-time, and it wouldn't prevent ArrayStoreException
at run-time.
What you're trying to propose is that given:
List<Integer> integerList;
and given this hypothetical super
bound on toArray
:
<S super T> S[] toArray(S[] a) // hypothetical! currently illegal in Java
the compiler should only allow the following to compile:
integerList.toArray(new Integer[0]) // works fine!
integerList.toArray(new Number[0]) // works fine!
integerList.toArray(new Object[0]) // works fine!
and no other array type arguments (since Integer
only has those 3 types as super
). That is, you're trying to prevent this from compiling:
integerList.toArray(new String[0]) // trying to prevent this from compiling
because, by your argument, String
is not a super
of Integer
. However, Object
is a super
of Integer
, and a String[]
is an Object[]
, so the compiler still would let the above compile, even if hypothetically you can do <S super T>
!
So the following would still compile (just as the way they are right now), and ArrayStoreException
at run-time could not be prevented by any compile-time checking using generic type bounds:
integerList.toArray(new String[0]) // compiles fine!
// throws ArrayStoreException at run-time
Generics and arrays don't mix, and this is one of the many places where it shows.
A non-array example
Again, let's say that you have this generic method declaration:
<T super Integer> void add(T number) // hypothetical! currently illegal in Java
And you have these variable declarations:
Integer anInteger
Number aNumber
Object anObject
String aString
Your intention with <T super Integer>
(if it's legal) is that it should allow add(anInteger)
, and add(aNumber)
, and of course add(anObject)
, but NOT add(aString)
. Well, String
is an Object
, so add(aString)
would still compile anyway.
See also
- Java Tutorials/Generics
- Subtyping
- More fun with wildcards
Related questions
On generics typing rules:
- Any simple way to explain why I cannot do
List<Animal> animals = new ArrayList<Dog>()
? - java generics (not) covariance
- What is a raw type and why shouldn’t we use it?
- Explains how raw type
List
is different fromList<Object>
which is different from aList<?>
- Explains how raw type
On using super
and extends
:
Java Generics: What is PECS?
- From Effective Java 2nd Edition: "producer
extends
consumersuper
"
- From Effective Java 2nd Edition: "producer
- What is the difference between
super
andextends
in Java Generics - What is the difference between
<E extends Number>
and<Number>
? - How can I add to
List<? extends Number>
data structures? (YOU CAN'T!)
Bounding generics with 'super' keyword
super
to bound a named type parameter (e.g. <S super T>
) as opposed to a wildcard (e.g. <? super T>
) is ILLEGAL simply because even if it's allowed, it wouldn't do what you'd hoped it would do, because since Object
is the ultimate super
of all reference types, and everything is an Object
, in effect there is no bound.
In your specific example, since any array of reference type is an Object[]
(by Java array covariance), it can therefore be used as an argument to <S super T> S[] toArray(S[] a)
(if such bound is legal) at compile-time, and it wouldn't prevent ArrayStoreException
at run-time.
What you're trying to propose is that given:
List<Integer> integerList;
and given this hypothetical super
bound on toArray
:
<S super T> S[] toArray(S[] a) // hypothetical! currently illegal in Java
the compiler should only allow the following to compile:
integerList.toArray(new Integer[0]) // works fine!
integerList.toArray(new Number[0]) // works fine!
integerList.toArray(new Object[0]) // works fine!
and no other array type arguments (since Integer
only has those 3 types as super
). That is, you're trying to prevent this from compiling:
integerList.toArray(new String[0]) // trying to prevent this from compiling
because, by your argument, String
is not a super
of Integer
. However, Object
is a super
of Integer
, and a String[]
is an Object[]
, so the compiler still would let the above compile, even if hypothetically you can do <S super T>
!
So the following would still compile (just as the way they are right now), and ArrayStoreException
at run-time could not be prevented by any compile-time checking using generic type bounds:
integerList.toArray(new String[0]) // compiles fine!
// throws ArrayStoreException at run-time
Generics and arrays don't mix, and this is one of the many places where it shows.
A non-array example
Again, let's say that you have this generic method declaration:
<T super Integer> void add(T number) // hypothetical! currently illegal in Java
And you have these variable declarations:
Integer anInteger
Number aNumber
Object anObject
String aString
Your intention with <T super Integer>
(if it's legal) is that it should allow add(anInteger)
, and add(aNumber)
, and of course add(anObject)
, but NOT add(aString)
. Well, String
is an Object
, so add(aString)
would still compile anyway.
See also
- Java Tutorials/Generics
- Subtyping
- More fun with wildcards
Related questions
On generics typing rules:
- Any simple way to explain why I cannot do
List<Animal> animals = new ArrayList<Dog>()
? - java generics (not) covariance
- What is a raw type and why shouldn’t we use it?
- Explains how raw type
List
is different fromList<Object>
which is different from aList<?>
- Explains how raw type
On using super
and extends
:
Java Generics: What is PECS?
- From Effective Java 2nd Edition: "producer
extends
consumersuper
"
- From Effective Java 2nd Edition: "producer
- What is the difference between
super
andextends
in Java Generics - What is the difference between
<E extends Number>
and<Number>
? - How can I add to
List<? extends Number>
data structures? (YOU CAN'T!)
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?
Iterating a generic list with super keyword
List<? super B> aList
can be reference to List<B>
, List<A>
and List<Object>
so in
for(A myObject : aList)
compiler can't let you use A
as type because it will not handle List<Object>
correctly since it can also contain elements which are not A
or B
since Object
is super class of all classes, like String
for instance (and using A
to handle String
would be wrong).
For same reason you can't use B
(you wouldn't be able to correctly handle List<A>
). Only Object
is safe type here.
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.
Related Topics
Intellij Inspection Gives "Cannot Resolve Symbol" But Still Compiles Code
How to Merge Two Sorted Arrays into a Sorted Array
How to Get Current Moment in Iso 8601 Format with Date, Hour, and Minute
How to Catch an Exception from a Thread
Round Up to 2 Decimal Places in Java
Java: Multiple Class Declarations in One File
What Is a "Surrogate Pair" in Java
Do I Need <Class> Elements in Persistence.Xml
How to Make a Jar File That Includes Dll Files
Java.Lang.Unsupportedclassversionerror: Bad Version Number in .Class File
Random Weighted Selection in Java
What Is Variable Shadowing Used for in a Java Class
Jtable Not Showing Up on Jframe (Java)