Below code :
List<? extends String> genericNames = new ArrayList<String>();
genericNames.add("John");
Gives compiler error :
Multiple markers at this line
- The method add(capture#1-of ? extends String) in the type List is not applicable for the
arguments (String)
- The method add(capture#1-of ?) in the type List is not applicable for the arguments (String)
What is causing this error ? Should I not be able to add Strings or its subtype since I am extending String within the type parameter ?
When you use wildcards with extends, you can't add anything in the collection except null. Also, String is a final class; nothing can extend String.
Reason: If it were allowed, you could just be adding the wrong type into the collection.
Example:
class Animal {
}
class Dog extends Animal {
}
class Cat extends Animal {
}
Now you have List<? extends Animal>
public static void someMethod(List<? extends Animal> list){
list.add(new Dog()); //not valid
}
and you invoke the method like this:
List<Cat> catList = new ArrayList<Cat>();
someMethod(catList);
If it were allowed to add in the collection when using wildcards with extends, you just added a Dog into a collection which accepts only Cat or subtype type. Thus you can't add anything into the collection which uses wildcards with upper bounds.
String is a final class and cannot be extended. Additionally, for the case you seem to be interested in, you do not need the extends keyword. List<String> will do what you seem to want. That will allow Strings and sub-classes of String (if such a thing could exist, which it can't since String is final).
Just want to add to the answer of GanGnaMStYleOverFlow that you can add an object of any subtype of Animal to the following list:
List<Animal> animals = new ArrayList<Animal>();
You should use such list whenever you think that it can contain any kind of animals.
On the other hand, you should use List<? extends Animal> when you want to specify that the list contains some kind of animal but you don't know which one. Since you don't know what kind of animals are there, you cannot add any.
Related
This question already has answers here:
Generics <? super A> doesn't allow superTypes of A to be added to the list
(2 answers)
Closed 4 years ago.
I am trying out a easy to understand example about contravariance in Java and having a issue understanding.
In the below example I have List<? super CarBill> list1 . My understanding is i should be able to add an object of any superclass of CarBill. By that logic i should be able to add objects of Bill class to it too right ?
I get a compilation error.
package Generics;
import java.util.ArrayList;
import java.util.List;
public class VarianceTests {
static class Bill{
String vName;
String type;
Bill(String vName){
this.vName=vName;
}
Bill(String vName,String type){
this.vName=vName;
this.type=type;
}
}
static class CarBill extends Bill{
String name;
CarBill(String name)
{
super(name,"Car");
}
}
static class Car<T extends Bill> {
T car;
Car(T car){
this.car=car;
}
String getNameOfCar() {
return car.vName;
}
}
public static void main(String args[]) {
CarBill cBill = new CarBill("Baleno");
Bill bill=new Bill("Whatever");
Car car = new Car(bill); //cBill is valid too as Car accepts <? extends Bill>
List<? super CarBill> list1 = new ArrayList<>();
list1.add(cBill);
list1.add(bill);
}
public void acceptListOfCars(List<? extends Bill> list1) {
Bill b = list1.get(0); //Valid syntax
}
}
Your understanding is mistaken.
List<? super CarBill> means that the list can be a list of any super class of CarBill or CarBill itself. It could be List<Object>, it could be List<Bill>, it could even be List<CarBill>. Which one is it actually? We don't know.
Therefore, you can't add a Bill to a List<? super CarBill> because what if the list is actually a List<CarBill>? You can't add a Bill to a List<CarBill>.
In other words, you can only add CarBill or subclasses of CarBill into a List<? super CarBill>.
If your intention is to create a list that can store any type of Bill, you can create a List<Bill>.
This post might help as well.
Not quite.
Let's start with this code:
List<Integer> listOfInts = new ArrayList<Integer>();
List<Number> listOfNumbers = listOfInts;
listOfNumbers.add(5.5D); // a double
int i = listOfInts.get(0); // uhoh!
The above code won't in fact compile; the second line is an invalid assignment. Your line of thinking would say: But.. why? Number is a supertype of Integer, so, a list of integers is trivially also a list of numbers, no? but then the third line shows why this line of reasoning is incorrect. Java will NOT let you write the above code. What you CAN write is this: The same thing, but this time we tweak the second line:
List<Integer> listOfInts = new ArrayList<Integer>();
List<? extends Number> listOfNumbers = listOfInts;
listOfNumbers.add(5.5D); // a double
int i = listOfInts.get(0); // uhoh!
This time, you get a compiler error on the third line: You cannot add a double to this list. But, if you read from it, you'd get numbers out (not objects). This is all good: The above snippet of code should never compile no matter what we try because it tries to add doubles to a list of ints.
The point is: List<? extends Number> does not mean: "This list contains numbers, or any subtypes thereof". No; just like List x = new ArrayList() is legal java, List<Number> means 'this list contains numbers or any subtypes thereof' because any instance of any subtype of number can itself be used as a Number. List<? extends Number> means: This is a list restrained to contain only instances of some specific type, but which type is not known. What IS known, is that whatever that type is, it's either Number or some subtype thereof.
Hence, you can't add ANYTHING to a List<? extends Number>.
For super, a similar story:
List<? super CarBill> means: This is a list that is restricted to contain only instances of some specific type, but which type is not known. What IS known, is that, whatever type it is, it is either CarBill or some SUPERtype thereof.
The upside of doing this, is that you can add CarBill instances to a List<? super CarBill> variable. When you read from it, you'll get objects out.
My understanding is i should be able to add an object of any superclass of CarBill
No.
A List<? super CarBill> is not a list that will accept objects of any supertype of CarBill. It's a list that will accept objects of some particular supertype of CarBill, but which supertype it is is unknown.
You can add any object of type CarBill, because that is guaranteed be a subtype of type ?. But a supertype of CarBill is not guaranteed to be a subtype of ?.
For instance:
List<? super CarBill> myList = new ArrayList<Bill>();
Object o = "Anything";
Object is a supertype of CarBill. So if you could add any supertype of CarBill to the list, you would be able to add o to the list, which would mean you could add anything to the list.
I can work with basic generic expression but the wildcard-constraints just mess with my mind.
Info: Student extends Person and Person extends Animal
List<? super Animal> aList= new ArrayList<>();
// does not compile as expected,
// since the list is restricted to something that has Animal as superclass.
// aList.add(new Object());
aList.add(new Animal()); // I can add animal
aList.add(new Person()); // I can add Person
aList.add(new Student()); // I can add Student
Animal a = new Animal();
Animal b = new Animal();
Person p = new Person();
Student s = new Student();
// test
a = b; //I can assign an animal to another animal
a = p; // I can assign a person to an animal
a = s; // I can assign a student to an animal
Animal animal = aList.get(0); // DOES NOT COMPILE, WHY ?
QUESTION: I don't understand why the last assignment does not work. The examples above show, that anything in that list is definitely an animal, yet I can't get an animal from that list.
MORE SPECIFIC: When I know that I can add only types which have Animal as superclass, why can't I expect to remove objects from type Animal ?
FACT: I can ONLY add objects which extend Animal! I just tried to add a car object and it does not work !
I am starting to doubt my sanity, I hope you can help me. Thank You
Additionally:
Object animal = aList.get(0); // works
Why does this statement work even though I know that I can't add an Object-Type ?
SOLUTION: (Based on the accepted answer)
I misunderstood the meaning of <? super Animal>
What I thought it means: Any class which has Animal as superclass.
What it (apparently) means: Any Class which is superclass of Animal.
Therefore a List might also contain objects of type Object which is why Animal animal = aList.get(0); fails.
Cheers
The other answers here are right, but not stated clearly enough, which is where the confusion is coming from.
A List<? extends Animal> does not mean "A list of things that all extend Animal." It means "A list of some type T, which I won't tell you what it is, but I know that T extends Animal." (In type theory, these are called existential types -- there exists a type T for which our List is a List<T>, but we don't necessarily know what T is.)
The difference is important. If you have "a list of things that all extend Animal", then it would be safe to add a Dog to the list -- but this is not what wildcards express. A List<? extends Animal> means "List of something, where that something extends Animal". It might be a List<Animal>, or a List<Dog>, or a List<Cat> -- we don't know. So we have no reason to think that its safe to add a Dog to that list -- because maybe my List is a List<Cat>.
In your example, you have a List<? super Animal>. This means, a list of some type T, where T is one of the supertypes of Animal. It might be a List<Object>, or a List<Animal>, or if Animal has a supertype HasLegs, it might be a List<HasLegs>. Here, it's safe to put a Dog into this list -- because whatever its a List of, Dog is definitely one of those (Animal, Object, etc), but when you take something out of the list, you have no idea whether its a Dog, an Animal, or just an Object.
List<? super Animal> aList is reference which can be used to handle List<Animal> , it can also be any superclass of Animal such as List<Object>.
In other words List<? super Animal> aList
- is not reference to some list which can store any supertype of Animal.
+ it is reference to list of some specific type which is supertype of Animal (including Animal itself) but you don't know which type it is exactly.
So it could be
List<Object> someList = new ArrayList<>();
someList.add(new Car());//OK since Car is a Object
List<? super Animal> aList = someList;// OK since Object is supertype of Animal
Because of that, code
Animal a = aList.get(0);//and where did that Car come from?
is not safe. Only safe type to store the result of get(0) is Object so you either need
Object o = aList.get(0);
or if you want to make sure that get will return Animal, change the type of your aList reference to List<Animal> or even List<? extends Animal>.
List<? super Animal> means a list of any superclass of Animal. If Animal is a subclass of LivingThing, then List<? super Animal> can be a list of Animals, a list of LivingThings, or a list of Object. In the last two cases, the assignment Animal x = aList.get(0) would of course be illegal, because you cannot assign a LivingThing to a reference of type Animal.
Consider the following method (it will not compile):
void f(List<? super Animal> list) {
Animal a = list.get(0); // line 1
list.add(new Object()); // line 2
}
The method call
List<Object> list = new ArrayList<>();
list.add(new Object());
f(list);
is correct, because Object is a superclass of Animal. However, if the method f would compile, you would try to assign in Line 1 an Object to an Animal reference, so it would not be type safe.
On the other, hand consider the method call:
f(new List<Animal>());
If the method f would compile, we would now be adding an Object instance to a list which should only contain Animals.
That's why both Line 1 and Line 2 are not allowed. If you have a class
public class A<T> {
public put(T in) { }
public T get() { }
}
then for the type A<? super Animal> the method get will return a Object (not an Animal), while the method put expects a parameter of type Animal.
Java. Wildcards in Collections
I’m having a lot of trouble understanding wildcards in Collections, even after reading similar posts in Stack Overflow and various tutorials sites. I've made a very simple example below. Can you explain how I would choose between Collection< myClass >, Collection< ? Extends MyClass >, and Collection< ? Super MyClass >?
package z5;
import java.util.ArrayList;
public class Z5 {
public static class Animal{
}
public static class Mammal extends Animal{
}
public static class Reptile extends Animal{
}
public static class Lion extends Mammal{
}
public static class Tiger extends Mammal{
}
public static class Snake extends Reptile{
}
public static void main(String[] args) {
ArrayList<Mammal> catHouse1 = new ArrayList<Mammal>();
catHouse1.add(new Lion());
catHouse1.add(new Tiger());
catHouse1.add(new Mammal());
catHouse1.add(new Animal()); //ERROR
ArrayList<? super Mammal> catHouse2 = new ArrayList<Mammal>();
catHouse2.add(new Lion());
catHouse2.add(new Tiger());
catHouse2.add(new Mammal());
catHouse2.add(new Animal()); //ERROR
ArrayList<? extends Mammal> catHouse3 = new ArrayList<Mammal>();
catHouse3.add(new Lion()); //ERROR
catHouse3.add(new Tiger()); //ERROR
catHouse3.add(new Mammal()); //ERROR
catHouse3.add(new Animal()); //ERROR
ArrayList<Mammal> zooMammals = new ArrayList<Mammal>();
zooMammals.addAll(catHouse1);
zooMammals.addAll(catHouse2); //ERROR
zooMammals.addAll(catHouse3);
ArrayList<Animal> zooAnimals = new ArrayList<Animal>();
zooAnimals.addAll(catHouse1);
zooAnimals.addAll(catHouse2); //ERROR
zooAnimals.addAll(catHouse3);
}
}
In the example above, I make a hierarchy of classes. Animal is the superclass of Mammal and Reptile, and Mammal is the superclass of Lion and Tiger.
I make ArrayLists for three Cat Houses in my zoo. The first is simply ArrayList< Mammal >. I can add any Object of type Mammal or its subclasses.
The second is ArrayList< ? super Mammal>. I can also add any Object of type Mammal or its subclasses.
The third is ArrayList< ? extends Mammal>. I can't add anything to it.
Finally, I add my three cat houses into zoo Collections. Animal and Mammal are the main superclasses here, and the behavior is the same regardless of which type the recipient ArrayList holds.
ArrayList < Mammal > and ArrayList can be added to the zoos.
ArrayList cannot.
Here are my questions:
1) If I want to make an array that holds all subclasses of a certain superclass, why would I need a wildcard? Couldn't I just declare everything ArrayList< Superclass > and get the functionality I need?
2) I understand that "< ? extends superclass >" accepts the superclass and all its subclasses. Ergo, < ? extends Mammal >" accepts Mammals, Lions, and Tigers. That sounds exactly like "< Mammal >". What's the difference?
3) I read that "< ? super className >" accepts any class that's a superclass of className. That doesn't sound right. In the example above, Lions are not superclasses of Mammals, but "< ? super Mammal >" accepts Lions. Animals are superclasses of Mammals, but "< ? super Mammal >" doesn't accept it. I think I have wrong information there.
4) If "< ? extends superclass >" is read-only, how dod I populate it to begin with? And what's the point of having an empty list that you can only read from?
5) Why does the addAll method not work on "< ? super className >"?
I know these are fundamental questions, and I understand they've been answered before. I'm trying to give a code example that's as simple as possible and hopefully get me an answer that's as clear as possible. Thanks in advance for any advice you can offer.
I won't go into great details.
List<Animal> means: this list contains instances of Animal. So you can add any Animal you want, and you're sure to get an Animal when getting elements from this list.
List<? extends Animal> means: this list is a generic list, but we don't know the type of the generic type. All we know about it is that the generic type is Animal, or any subclass of Animal. So it could be a List<Animal>, a List<Reptile> or a List<Lion>, for example. But we don't know. So, when getting an element from this list, you're guaranteed to get an Animal. But you won't be allowed to add anything into the list, because you don't know its type. If you were allowed to add something, you could store a Lion in a List<Reptile>, and the list wouldn't be type-safe anymore.
List<? super Animal> means: this list is a generic list, but we don't know the type of the generic type. All we know about it is that the generic type is Animal, or any superclass or super interface of Animal. So it could be a List<Animal> or a List<Object>, for example. So, when getting an element from this list, all you can say for sure is that it's an Object. What you can do for sure is to add any Animal you want in this list though, because both List<Animal> and List<Object> accept Animal, Lion, Reptile or whatever subclass of Animal.
Most of the time, you use these wildcards for arguments of your methods.
When a method takes a list as argument and is only interested in reading from the list (i.e. the list is a producer), you'll use List<? extends Animal>. This makes your method more reusable, because it can be used with a List<Animal>, but also with a List<Reptile>, a List<Lion>, etc.
When a method takes a list as argument and is only interested in adding elements to the list (i.e. the list is a consumer), you'll use List<? super Animal>. This makes your method more reusable, because it can be used with a List<Animal>, but also with a List<Object>.
This rule is known as PECS: Procucer: Extends; Consumer: Super.
If your method takes a list as argument and must both get and add elements to/from the list, you'll use a List<Animal>.
If you just want a list that can contain Animal or subclasses Animal you should use List<Animal>. I think this is what you need most of the time.
extends:
ArrayList<? extends Mammal> list = ..
This means that list is of type Mammal or one of its sub classes. So you can do this:
ArrayList<? extends Mammal> list = new ArrayList<Tiger>(); // List of type Tiger
When using <? extends Mammal> you can't insert anything into list (except null). The reason that there is no typesafe way to insert anything. You can't add a Mammal to list because list might be of type Tiger (like in the example above). A Mammal is no Tiger so this can't work.
You can't add a Tiger to list either. That's because <? extends Mammal> doesn't tell you anything about Tiger. It would be also possible that list is of type Lion.
super:
With <? super Mammal> it is the opposite situation. <? super Mammal> means that the list is of type Mammal or one of its superclasses. You can do this:
ArrayList<? super Mammal> list = new ArrayList<Animal>(); // List of type Animal
You can add any subclass of Mammal to this list. This is safe because subclasses of Mammal are always subclasses of Animal. However you can't get anything out of the list with another type than Object. Thats because you don't know the exact list type.
Mammal m = list.get(0); // can't work because list can be a List<Animal>
import java.util.List;
import java.util.ArrayList;
interface Canine {}
class Dog implements Canine {}
public class Collie extends Dog {
public static void main(String[] args){
List<Dog> d = new ArrayList<Dog>();
List<Collie> c = new ArrayList<Collie>();
d.add(new Collie());
c.add(new Collie());
do1(d); do1(c);
do2(d); do2(c);
}
static void do1(List<? extends Dog> d2){
d2.add(new Collie());
System.out.print(d2.size());
}
static void do2(List<? super Collie> c2){
c2.add(new Collie());
System.out.print(c2.size());
}
}
The answer for this question tell that when a method takes a wildcard generic typ, the collection can be accessed or modified, but not both. (Kathy and Bert)
What does it mean 'when a method takes a wildcard generic typ, the collection can be accessed or modified, but not both' ?
As far as I know,
The method do1 has List<? extends Dog> d2 so d2 only can be accessed but not modified.
The method d2 has List<? super Collie> c2 so c2 can be accessed and modified and there is no compilation error.
Generic guidelines
You cannot add a Cat to a List<? extends Animal> because you don't know what kind of list that is. That could be a List<Dog> also. So you don't want to throw your Cat into a Black Hole. That is why modification of List declared that way is not allowed.
Similarly when you fetch something out of a List<? super Animal>, you don't know what you will get out of it. You can even get an Object, or an Animal. But, you can add an Animal safely in this List.
I pasted your code into my IDE. The following error was signalled inside do1:
The method add(capture#1-of ? extends Dog) in the type List is not applicable for the arguments (Collie)
This is, of course, as expected.
You simply cannot add a Collie to a List<? extends Dog> because this reference may hold for example a List<Spaniel>.
The answer for this question tell that when a method takes a wildcard generic typ, the collection can be accessed or modified, but not both. (Kathy and Bert)
That's a fair first approximation, but not quite correct. More correct would be:
You can only add null to a Collection<? extends Dog> because its add method takes an argument of ? extends Dog. Whenever you invoke a method, you must pass parameters that are of a subtype of the declared parameter type; but for the parameter type ? extends Dog, the compiler can only be sure that the argument is of compatible type if the expression is null. However, you can of course modify the collection by calling clear() or remove(Object).
On the other hand, if you read from a Collection<? super Dog>, its iterator has return type ? super Dog. That is, it will return objects that are a subtype of some unknown supertype of Dog. But differently, the Collection could be a Collection<Object> containing only instances of String. Therefore
for (Dog d : collection) { ... } // does not compile
so the only thing we know is that instances of Object are returned, i.e. the only type-correct way of iterating such a Collection is
for (Object o : collection) { ... }
but it is possible to read from a collection, you just don't know what types of objects you will get.
We can easily generalize that observation to: Given
class G<T> { ... }
and
G<? extends Something> g;
we can only pass null to method parameters with declared type T, but we can invoke methods with return type T, and assign the result a variable of type Something.
On the other hand, for
G<? super Something> g;
we can pass any expression of type Something to method parameters with declared type T, and we can invoke methods with return type T, but only assign the result to a variable of type Object.
To summarize, the restrictions on the use of wildcard types only depend on the form of the method declarations, not on what the methods do.
I pasted your code into IDEONE http://ideone.com/msMcQ. It did not compile for me - which is what I expected. Are you sure you did not have any compilation errors?
I have a Java question about generics. I declared a generic list:
List<? extends MyType> listOfMyType;
Then in some method I try instantiate and add items to that list:
listOfMyType = new ArrayList<MyType>();
listOfMyType.add(myTypeInstance);
Where myTypeInstance is just an object of type MyType; it won't compile. It says:
The method add(capture#3-of ? extends
MyType) in the type List<capture#3-of
? extends MyType> is not applicable
for the arguments (MyType)
Any idea?
You cannot do a "put" with extends . Look at Generics - Get and Put rule.
Consider:
class MySubType extends MyType {
}
List<MySubType> subtypeList = new ArrayList<MySubType>();
List<? extends MyType> list = subtypeList;
list.add(new MyType());
MySubType sub = subtypeList.get(0);
sub now contains a MyType which is very wrong.
You shouldn't need to use the wildcard capture syntax in your case, simply declaring
List<MyType> listOfMytype;
should be enough. If you want to know exactly why, the Java Generics Tutorial has more than you would ever want to know about the esoteric craziness of Java Generics. Page 20 addresses your specific case.
As for why add with the wildcard capture does not work, it is because the compiler can't determine exactly what subclass of MyType the list will be in every case, so the compiler emits an error.
There is a similar thread here:
How can elements be added to a wildcard generic collection?
To get an idea of how generics works check out this example:
List<SubFoo> sfoo = new ArrayList<SubFoo>();
List<Foo> foo;
List<? extends Foo> tmp;
tmp = sfoo;
foo = (List<Foo>) tmp;
The thing is, that wasn't designed for local/member variables, but for function signatures, that's why it's so ass-backwards.
I dont know if this will really help you, but this is something I had to use while calling a generic method of Spring Framework and wanting to return also a generic list:
public <T> List<T> findAll(String tableName,Class<?> table) {
String sql = "SELECT * FROM "+ tableName ;
List<?> entities = getSimpleJdbcTemplate().query(sql,
ParameterizedBeanPropertyRowMapper.newInstance(table));
return (List<T>) entities;
}
Seems the parametrization needs you to use the ? sign in the list to receive the results and then cast the list to the expected return type.
Iam still dazzled by generics...