The code below makes complete sense to me - its about adding an element of some type which is supertype of type T and type S is definitely such a super type , so why the compiler refuses to add 'element' into the collection ?
class GenericType<S,T extends S>{
void add1(Collection<? super T> col ,S element ){
col.add(element); // error
// The method add(capture#9-of ? super T) in the type
// Collection<capture#9-of ? super T> is not applicable for the arguments (S)
}
}
Thake an example, if A <- B <- C where <- means that is the supertype, then if S = B and T = C you cannot add an instance of S to a collection of T.
A supertype of T may be the supertype or a subtype of another supertype of T (in this case S).
Collection<? super T> does not mean "a collection that can contain T and any superclass of it" - it's actually not possible to formulate that restriction. What it means is "a collection that can only contain instances of some specific class which is a superclass of T" - basically it ensures that you can add a T to the collection.
The method can be called with a Collection<T>, yet you want to add an S to it.
new GenericType<Object,Integer>().add1(new ArrayList<Integer>(), "");
You are trying to put an element of type S into a collection of type T. Generics aren't polymorphic.
You have to take notice of 2 problems here. you are trying to create an Collection of type concreteObject extends Object and are adding an object
So when you have
Car extends Vehicle{}
ElectricCar extends Car{}
you are trying to do
Collection<? extends Car> collection;
collection.add(new Vehicle());
The second problem lies with the non-polymorphism nature of Generics. See this great explanation -> Is List<Dog> a subclass of List<Animal>? Why aren't Java's generics implicitly polymorphic?
Related
This question already has answers here:
What is PECS (Producer Extends Consumer Super)?
(16 answers)
Closed 5 months ago.
I am confused by whether wildcards <? super Number> refers to a superclass like Object or a subtype like Integer. In "Java OCP 17 Developer Complete Study Guide" by Jeanne Boyarsky and Scott Selikoff, (Chapter 9 Collections and Generics)
Generics allow you to specify wildcards. <?> is an unbounded wildcard
that means any type. <? extends Object> is an upper bound that means
any type that is Object or extends it. <? extends MyInterface> means
any type that implements MyInterface.
<? super Number> is a lower bound that means any type that is Number or a super class. A compiler error results from code that attempts
to add an item in a list with an unbounded or upper-bounded wildcard
A super class as I understand, is a parent of Number.
But then, why cannot one do this?
import java.util.ArrayList;
import java.util.List;
public class Bewildered {
static class A {}
static class B extends A {}
static class C extends B {}
public static void main(String[] args) {
List<? super B> listBs = new ArrayList<>();
listBs.add(new A());
}
}
compile error:
java: incompatible types: Bewildered.A cannot be converted to capture#1 of ? super Bewildered.B
Because you're thinking about what generics means in the wrong way.
List<? super B> does not mean: "A list that contains Bs or anything that is a supertype of B".
Because that would be utterly useless. Object is a supertype of B. All things are objects. So it's a list of absolutely anything, there's absolutely nothing useful about this list.
No, what List<? super B> means: There is a type. A specific type. It's just.. this code doesn't know what it is. We do know that it is either B or some supertype of B. (So, it's B, or A, or Object, we don't know. The caller picked one of these 3 types). This list is constrained; it cannot contain anything that is not this unknown type.
The point is, you can do this:
List<B> bees = new ArrayList<B>();
List<? super B> list = bees; // legal!
list.add(new A()); // um...
B bee = bees.get(0); // oh no!
See how this goes wrong? There's only one list here - bees and list are both just variables that refer to the exacrt same list. So you if you call list.add, you're modifying the one list that both bees and list are pointing at, so you also add it to bees.
So what's the point of <? super B>?
You can call .add(new B()). Because that works for all legal choices. Whatever the caller picked - if they gave you a List<B>, it works. If it's a List<A>, works. List<Object>? Still acceptable.
No other types fit the bill for <? super B>, so we've exhausted the options: They all 'work out'.
question about Wildcard
Example:Student extends Person
Person person = new Person();
Student student = new Student();
List<? super Student> list = new ArrayList<>();
list.add(student); // success
list.add(person); // compile error
List<? extends Person> list2 = new ArrayList<>();
list2.add(person); // compile error
list2.add(student);// compile error
I have read the answer below a question "capture#1-of ? extends Object is not applicable"
You are using generic wildcard. You cannot perform add operation as class type is not determinate. You cannot add/put anything(except null) -- Aniket Thakur
Official doc:The wildcard is never used as a type argument for a generic method invocation, a generic class instance creation, or a supertype
But why could list.add(student) compile successfully ?
Design of java.util.function.Function
public interface Function<T, R>{
//...
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}
}
Why before is designed to Function<? super V, ? extends T> rather than Function<V,T> when the type of return is Function<V,R> and type of the input is V ? (It still can pass compile and use flexibly)
To understand these questions, you have to understand how generics work with subtyping (which is explicitly denoted in Java using the extends keyword). Andreas mentioned the PECS rules, which are their representations in Java.
First of all, I want to point out that the codes above can be corrected by a simple cast
ArrayList<? super Student> list = new ArrayList<>();
list.add(new Student());
ArrayList<Person> a = (ArrayList<Person>) list; // a covariance
a.add(new Person());
And compiles & runs well (rather than raising any exceptions)
The reason is simple, when we have a consumer (which takes some objects and consume them, such as the add method), we expect it to take objects of type no more than(superclasses) the type T we specified, because the process of consuming needs possibly any member(variables, methods etc.) of the type it wants, and we want to ensure that type T satisfy all the members the consumer requires.
On the contrary, a producer, which produces objects for us (like the get method), has to supply objects of type no less than the specified type T so that we can access any member that T has on the object produced.
These two are closely related to subtyping forms called covariance and contravariance
As for the second question, you can refer to the implementation of Consumer<T> as well (which is somewhat simpler):
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
the reason why we need this ? super T is that: when we are combining two Consumers using the method andThen, suppose that the former Consumer takes an object of type T, we expect the later to take a object of type no more than T so it would not try to access any member that T doesn't have.
Therefore, rather than simply writing Consumer<T> after but Consumer<? super T> after, we allow the former consumer (of type T) to be combined with a consumer that takes an object not exactly of type T, but maybe smaller then T, by the convenience of covariance. That makes the following codes sound:
Consumer<Student> stu = (student) -> {};
Consumer<Person> per = (person) -> {};
stu.andThen(per);
The compose method of type Function also applies, by the same consideration.
IMO This is probably the most complex concept in vanilla Java. So let's break this down a bit. I'll start with your second question.
Function<T, R> takes an instance t of type T and returns an instance r of type R. With inheritance that means that you could supply an instance foo of type Foo if Foo extends T and similarly return bar of type Bar if Bar extends R.
As a library maintainer who wants to write a flexible generic method, it's hard, and actually impossible, to know in advance all the classes which might be used with this method which extend T and R. So how are we going to write a method that handles them? Further, the fact that these instances have types which extend the base class is none of our concern.
This is where the wildcard comes in. During the method call we say that you can use any class which meets the envelope of the required class. For the method in question, we have two different wildcards using upper and lower bounded generic type parameters:
public interface Function<T, R>{
default <V> Function<V, R> compose(Function<? super V, ? extends T> before)
Lets now say that we want to take advantage of this method... for the example lets define some basic classes:
class Animal{}
class Dog extends Animal{}
class Fruit{}
class Apple extends Fruit{}
class Fish{}
class Tuna extends Fish{}
Imagine our function and transformation is defined as below:
Function<Animal, Apple> base = ...;
Function<Fish, Animal> transformation = ...;
We can combine these functions using compose to create a new function:
Function<Fish, Apple> composed = base.compose(transformation);
This is all fine and dandy, but now imagine that in the desired output function we actually only want to use Tuna as the input. If we did not use the lower-bounded ? super V as the input type parameter for the Function we pass to compose then we would get a compiler error:
default <V> Function<V, R> compose(Function<V, ? extends T> before)
...
Function<Tuna, Apple> composed = base.compose(transformation);
> Incompatible types:
> Found: Function<Fish, Apple>, required: Function<Tuna, Apple>
This happens because the return type for the call to compose specifies V as Tuna while transformation on the other hand specifies its "V" as Fish. So now when we try to pass transformation to compose the compiler requires transformation to accept a Tuna as its V and of course Tuna does not identically match Fish.
On the other hand, the original version of the code (? super V) allows us to treat V as a lower bound (i.e. it allows "contravariance" vs. "invariance" over V). Instead of encountering a mismatch between Tuna and Fish the compiler is able to successfully apply the lower bound check ? super V which evaluates to Fish super Tuna, which is true since Tuna extends Fish.
For the other case, imagine our call is defined as:
Function<Animal, Apple> base = ...;
Function<Fish, Dog> transformation = ...;
Function<Fish, Apple> composed = base.compose(transformation);
If we did not have the wildcard ? extends T then we would get another error:
default <V> Function<V, R> compose(Function<? super V, T> before)
Function<Fish, Apple> composed = base.compose(transformation);
// error converting transformation from
// Function<Fish, Dog> to Function<Fish, Animal>
The wildcard ? extends T allows this to work as T is resolved to Animal and the wildcard resolves to Dog, which can satisfy the constraint Dog extends Animal.
For your first question; these bounds really only work in the context of a method call. During the course of the method, the wildcard will be resolved to an actual type, just as ? super V was resolved to Fish and ? extends T was resolved to Dog. Without the information from the generic signature, we would have no way for the compiler to know what class can be used on the type's methods, and therefore none are allowed.
The PECS principle is about what kind of argument you select in a function, depending on how you will use that parameter.
My question is about the fact that, once you chose to use super (because your function possibly is a Consumer), you cannot pass to that function certain generic class instances.
Let's consider the following program:
public class Main{
public static void main(String[] args){
List<?> unbound = new ArrayList<Long>();
List<? extends Long> extendsBound = new ArrayList<Long>();
List<? super Long> superBound = new ArrayList<Long>();
takeExtend(unbound);
takeExtend(extendsBound);
takeExtend(superBound);
takeSuper(unbound);
takeSuper(extendsBound);
takeSuper(superBound);
}
static <T> void takeExtend(List<? extends T> l){}
static <T> void takeSuper(List<? super T> l){}
}
The compiler gives the following error:
error: method takeSuper in class Main cannot be applied to given
types;
takeSuper(unbound);
^ required: List<? super T> found: List<CAP#1> reason: cannot infer type-variable(s) T
(argument mismatch; List<CAP#1> cannot be converted to List<? super T>) where T is a type-variable:
T extends Object declared in method <T>takeSuper(List<? super T>) where CAP#1 is a fresh type-variable:
CAP#1 extends Object from capture of ?
I was trying to find a sort of symmetry, such as the one we have for the PECS rule, but I didn't find any.
So:
Why is it not possible to pass a <?> or a <? extends T> to a function expecting <? super T>?
Why is it possible to pass a <?> to a function expecting a <? extends T>?
Why is it possible to pass a <? super T> to a function expecting a <? extends T>?
You can think of a generic method (i.e. a method with its own type parameters) as making a set of statements about its type parameters.
For example, the method <T> someMethod(List<T>) is saying:
There exists some type T for which the type parameter of this list equals T.
Easy. All lists fit this criterion, so any list is a valid input to the method.
Everything inside the method can now make use of the knowledge that that statement is true. How is that knowledge useful? Well, if we get an item from the list, we know it matches the list's type parameter. Because we captured the type as T, we can hold a reference to the object and put it back in the list later, all still without knowing what type it really is.
The method declaration <T> someMethod(List<? extends T>) makes a slightly different claim:
There exists some type T for which the type parameter of this list is a subtype of T.
This is also trivially true for all lists. However, you might notice that it makes <T> someMethod(List<? extends T>) a bit useless. You're telling the compiler to capture the fact that items that come out of the list share some common supertype with other items that come out of the list. Unless you have, inside the method, some other consumer that is known to accept <? super T>, there's nothing you can do with that information. It's much less useful than the knowledge that all the items that come from the list are of the same type.
So, why doesn't <T> takeSuper(List<? super T>) work the same way?
The method declaration <T> takeSuper(List<? super T>) can be interpreted as claiming that:
There exists some type T for which the type parameter of this list is a supertype of T.
If we have a List<? super Long> and we pass it to a method that captures <T> takeSuper(List<? super T>) it's easy to see that a reference of type Long would satisfy T. We could pass a Long to the method as a parameter of type T, and then add it to the list from inside the method.
But what about if we have a List<?> and we capture its type using the method <T> takeSuper(List<? super T>)? By declaring the list as a List<?> we're saying that we don't currently know what its type parameter is. In doing that, we're telling the compiler that we have absolutely no way to get a reference of a type that matches the type parameter of the list. In other words, the compiler knows with certainty that no object can satisfy the type parameter T. Remember, for this method, an object is of type T if it is known to be of a type that is a subtype of the type parameter of the list. If we don't know anything about the type parameter of the list, that's impossible.
The same is true for a List<? extends Long>. We know that the items we fetch from the list will be a subtype of Long, but we don't have a lower bound for their type. We can never prove that any type is a subtype of the list's type parameter. So, for the method <T> takeSuper(List<? super T>), there is again provably no way to get a reference of type T.
Interestingly, my compiler (Java 8) doesn't complain about calling the method <T> takeSuper(List<? super T>) with a List<?> as input. I suppose it recognizes that since there's no way to get a reference of type T, there's no harm in just ignoring the useless type parameter.
Why is it not possible to pass a <?> or a <? extends T> to a function expecting <? super T>?
Consider this method:
static <T> void sillyAdd(List<? super T> l, T t){
l.add(t);
}
Now look how we could use it if this were possible:
List<Integer> onlyIntegers = new ArrayList<>();
List<? extends Number> anyNumber = onlyIntegers;
sillyAdd(anyNumber, Float.valueOf(0)); /* Not allowed... */
Integer i = onlyIntegers.get(0);
The last line would throw a ClassCastException because we were allowed to put a Float into a List<Integer>.
Why is it possible to pass a <?> to a function expecting a <? extends T>?
takeExtend(unbound);
There are no bounds on T; it could be any type. While the type parameter of unbound is unknown, it does have some type, and since T can be any type, it's a match.
Methods like this are sometimes used as a helper in some odd corners of generics. Logically, we know that the following should be no problem:
public static void rotate(List<?> l) {
l.add(l.remove(0));
}
But the rules of generics don't imply type-safety here. Instead, we can use a helper like this:
public static void rotate(List<?> l) {
helper(l);
}
private static <T> void helper(List<T> l) {
l.add(l.remove(0));
}
Why is it possible to pass a <? super T> to a function expecting a <? extends T>?
It's not, in a way. Given this example:
static <T> void takeExtend(List<? extends T> l)
List<? super Long> superBound = new ArrayList<Long>();
takeExtend(superBound);
You might think that T is inferred to be Long. That would mean that you passed a List<? super Long> to a method declared like void takeExtend(List<? extends Long> l), which seems wrong.
But T isn't inferred to be Long. If you specify Long explicitly as the type parameter, you'll see that it won't work:
Main.<Long>takeExtend(superBound);
What's actually happening is that T is inferred to be ? super Long, so the generic type of the method is something like void takeExtend(List<? extends ? super Long>). That means that everything in the list is something that extends an unknown super class of Long.
Why is it not possible to pass a <?> or a <? extends S> to a function expecting <? super T>? (Question corrected for clarity: ? extends S).
The compiler wants to infer the T, which is the bottom limit, and it can't. Every class extends Object, but there is no universal inheritance tree bottom class, which the compiler could default to.
Why is it possible to pass a <?> to a function expecting a <? extends T>?
It's about inference. You can pass a <?> because the compiler can make something out of it. Namely, it can make Object out of T. The same happens with the following:
List<?> unbound = new ArrayList<>();
Why is it possible to pass a <? super T> to a function expecting a <? extends T>?
Again, it's about inferring the upper limit now, so the compiler can default to Object. It's not interested in what ? is super to, nor whether it is super to anything at all.
I've been thinking this stuff all night long, with the amazing help of your comments, trying to find an easy-to-remember solution.
This is what I got.
A method accepting a <? extends T>, to get T, must infer the upper limit of that hierarchy. Since in Java every class is extending Object, the compiler can rely on the fact that at least the upper limit is Object. So:
if we pass a <? extends T>, the upper bound is already defined and it
will use that one
if we pass <?>, we don't know anything, but we know
that every class extends Object, so the compiler will infer Object
if we pass <? super T>, we know the lower bound, but since every class
extends Object, the compiler infer Object.
A method accepting a <? super T>, to get T, must infer the lower limit of that hierarchy. In Java by default we can count on an upper bound, but not on a lower bound. So the considerations made in the previous case are not valid anymore. So:
if we pass a <? extends T>, there is no lower bound, because the
hierarchy can be extended as much as we want
if we pass a <?>,
there is no lower bound, because the hierarchy can be extended as
much as we want
if we pass a <? super T>, a lower bound is already
defined, so we can use that one.
Recapping:
a method accepting a <? extends T> can always rely on the fact that
an upper bound exists and that is Object -> we can pass every bound to it
a method accepting a <? super T> can infer a lower bound only if it is explicitly defined in the parameter -> we can only pass a <? super T>
I am trying to digest a standard example of using a covariant/contravariant type argument for a Collection and then trying to work out why certain methods behave in a way they do. Here is my example and my (potentially wrong) explanation, and in case of confusion, questions:
List<? extends MyObject> l = new ArrayList<>();
x = l.get(0);
type of x is MyObject -> this is because compiler realizes that that the upper bound on the type is MyObject and can safely assume this type.
l.add(new MyObject()); //compile error
The error is caused because, although the upper-bound type of the collection is known, the ACTUAL type is not known (all the compiler knows is that it is the subclass of MyObject). So, we could have a List<MyObject>, List<MyObjectSubclass> or god knows what other subtype of MyObject as type parameter. As a result, in order to be sure that objects of wrong type are not stored in the Collection, the only valid value is null, which is a subtype of all types.
Conversly:
List<? super MyObject> l = new ArrayList<>();
x = l.get(0)
type of x is Object, as compiler only knows about the lower-bound. Therefore,. teh only safe assumption is the root of type hierarchy.
l.add(new MyObject()); //works
l.add(new MyObjectSubclass()); // works
l.add(new Object()); //fails
The above final case is where I am having problems and I am not sure whether I get this right. COmpiler can expect any list with a generic type of MyObject all the way to the Object. So, adding MyObjectSubclass is safe, because it would be OK to add to List<Object> even. The addition of Object, would however, violate List<MyObject>. Is that more or less correct? I would be glad to hear more technincal explanation if anyone has it
Generics are neither covariant nor contravariant. They are invariant.
Wildcards can be used to facilitate usage of parameterized types. About 95% of what you need to know about them has been summed up by Mr. Bloch in Effective Java (must read) with the PECS rule (Producer Extends Consumer Super).
Assume
interface Owner<T> {
T get();
void set(T t);
}
and the usual Dog extends Animal example
Owner<? extends Animal> o1;
Animal a = o1.get(); //legal
Dog d = (Dog) o1.get(); //unsafe but legal
o1.set(new Dog()); //illegal
Conversely:
Owner<? super Animal> o1;
o1.set(new Dog()); //legal
Animal a = o1.get(); //illegal
To answer more directly List<? super Dog> is a list that consumes (adds in this case) Dog instances (meaning it will consume a Poodle instance as well).
More generally, the methods of a Foo<? super Bar>instance that are defined to accept an argument of Foo's type parameter, can be called with any object referenced compile time with Bar or a sub-type of Bar.
Don’t get fooled by thinking about the behavior of objects you have just created. There’s no sense in giving them wildcards. Wildcards are there to give freedom to method parameters. Look at the following example:
public static <T> void sort(List<? extends T> list, Comparator<? super T> c)
This means there must be a type T for which the list guarantees that all elements are of type T (might be a subclass) and that the provided Comparator implementation can handle elements of T (might be more abstract).
So it is permitted to pass in a List<Integer> together with a Comparator<Number>.
This question already has answers here:
Difference between <? super T> and <? extends T> in Java [duplicate]
(14 answers)
Closed 6 years ago.
I'm having trouble understanding the following syntax:
public class SortedList< T extends Comparable< ? super T> > extends LinkedList< T >
I see that class SortedList extends LinkedList. I just don't know what
T extends Comparable< ? super T>
means.
My understanding of it so far is that type T must be a type that implements Comparable...but what is < ? super T >?
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.
It's a lower-bounded wildcard.
JLS 4.5.1 Type Arguments and Wildcards
Wildcards are useful in situations where only partial knowledge about the type parameter is required. [...] An upper bound is signified by the syntax:
? extends B
where B is the upper bound. [...] it is permissible to declare lower bounds on a wildcard, using the syntax:
? super B
where B is a lower bound.
A List<? super Integer>, for example, includes List<Integer>, List<Number>, and List<Object>.
Wildcards are used to make generics more powerful and flexible; bounds are used to maintain type safety.
See also
Java language guide/Generics/More Fun with wildcards
As to how this is useful in <T extends Comparable<? super T>>, it's when you have something like Cat extends Animal implements Comparable<Animal>.
Look at the signature of Collections.sort
public static <T extends Comparable<? super T>> void sort(List<T> list)
Therefore, with a List<Cat> listOfCat, you can now Collections.sort(listOfCat).
Had it been declared as follows:
public static <T extends Comparable<T>> void sort(List<T> list)
then you'd have to have Cat implements Comparable<Cat> to use sort. By using the ? super T bounded wildcard, Collections.sort becomes more flexible.
See also
Effective Java 2nd Edition, Item 28: Use bounded wildcards to increase API flexibility
Also, PECS principle: "producer extends consumer super"
It means that T must implement Comparable<T itself or one of T's superclasses>
The sense is that because SortedList is sorted, it must know how to compare two classes of its generics T parameter. That's why T must implement Comparable<T itself or one of T's superclasses>
It means that the type T must implement Comparable of T or one of its super classes.
For example, if A extends B, if you want to use SortedList<A>, A must implement Comparable<A> or Comparable<B>, or in fact just Comparable.
This allows the list of As to be constructed with any valid comparator.
Consider the following example:
Using a type parameter defined in the class declaration
public class ArrayList extends AbstractList ... {
public boolean add(E o) // You can use the "E" here ONLY because it's already been defined as part of the class
Using a type parameter that was NOT defined in the class declaration
public <T extends Animal> void takeThing(ArrayList<T> list)
// Here we can use <T> because we declared "T" earlier in the method declaration
If the class itself doesn't use a type parameter, you can still specify one for a method, by declaring it in a really unusual (but available) space - before the return type. This method says that T can be "any type of Animal".
NOTE:
public <T extends Animal> void takeThing(ArrayList<T> list)
is NOT same as
public void takeThing(ArrayList<Animal> list)
Both are legal, but they are different. The first one indicates that you can pass in a ArrayList object instantiated as Animal or any Animal subtype like ArrayList, ArrayList or ArrayList. But, you can only pass ArrayList in the second, and NOT any of the subtypes.