I have the following class:
interface Able{/* ... */}
class A implements Able{/* ... */}
and I have
Map<String,? extends Able> as;
as = new HashMap<String, A>();
why does the following cause an error:
as.put("a", new A());
Any ideas?
The reference to java generics is good (jdk site).
Indeed #Oli_Charlesworth gave a good answer, but maybe this one will be more complete.
In a Collection<? extends Able> you can't insert anything that's right.
If you have
class A implements Able {...}
and
class B implement Able {...}
Then, Collection<? extends Able> is a super type of both :
Collection<A>
Collection<B>
Thus it is legal to write some statement like
//Code snippet 01
Collection< ? extends Able > list;
Collection<A> listA;
Collection<B> listB;
list = listA;
list = listB;
That is indeed the reason why the wildcard notation Collection<? extends Able> exists.
But, here things are getting more interesting :
In a Collection<A> you can only insert objects that are A (including subclasses). Same for Collection<B>. In both you can't add something that is just Able. For instance :
//Code snippet 02
listA.add( new A() ); //valid at compile-time
listA.add( new B() ); //not valid at compile-time
listB.add( new B() ); //valid at compile-time
listB.add( new A() ); //not valid at compile-time
Thus, if you group what we saw in code snippets 01 & 02, you will understand that it's absolutely impossible for the compiler to accept a statement like :
Collection< ? extends Able > list;
list.add( new A() ); //not allowed, will work only if list is List<A>
list.add( new B() ); //not allowed, will work only if list is List<B>
So yes, the super type Collection< ? extends Able > doesn't accept to add anything. More general types offer the intersection of functionalities of subtypes, and, as such, less features that subtype. Here, we lose the ability to add A objects and B objects. Those feature will happen later in the hierarchy... and it even means that we can't add anything in the super class Collection< ? extends Able >
Additional remark :
Also, note that in a Collection<Able> you can add whatever you want like this :
Collection< Able > list;
list.add( new A() ); //valid
list.add( new B() ); //valid
But, Collection<Able> is not a superclass of Collection<A> and Collection<B>. It would mean, as with any inheritance relation, that subclasses can do whatever their superclass can do, as inheritance is specialization. So, this would mean that we could add A objects and B objects to both subclasses Collection<A> and Collection<B> and that is not the case. So as it's not a superclass you can't have :
Collection<Able> list;
Collection<A> listA;
Collection<B> listB;
list = listA; //not valid because there is no inheritance hierarchy
list = listB; //not valid because there is no inheritance hierarchy
Note that inheritance is a hyperonimic relation (generalization/specialization) and collections define a meronimic relation (container/containee). And it's a headache to combine both of them formally, even though it's somewhat used quite easily by the fuzzy creatures humans are, for instance in the french figure of speech : synecdocque. :)
From http://download.oracle.com/javase/tutorial/extra/generics/wildcards.html:
There is, as usual, a price to be paid
for the flexibility of using
wildcards. That price is that it is
now illegal to write into [a wildcard-based container]. For instance,
this is not allowed:
public void addRectangle(List<? extends Shape> shapes) {
shapes.add(0, new Rectangle()); // Compile-time error!
}
You should be able to figure out why
the code above is disallowed. The type
of the second parameter to
shapes.add() is ? extends Shape-- an
unknown subtype of Shape. Since we
don't know what type it is, we don't
know if it is a supertype of
Rectangle; it might or might not be
such a supertype, so it isn't safe to
pass a Rectangle there.
A good way to understand the issue is to read what the wildcard means:
Map<String,? extends Able> as;
"A map with keys of type String and values of one type that extends Able."
The reason why add operations are not allowed is because they "open the door" to introduce different types in the collection, which would conflict with the typing system.
e.g.
class UnAble implements Able;
Map<String,UnAble> unableMap = new HashMap<String,UnAble>();
Map<String,? extends Able> ableMap = unableMap;
ableMap.put("wontwork",new A()); // type mismatch: insert an A-type into an Unable map
A correct use of the the wildcard construction would be:
Result processAble(Map<String,? extends Able>) { ... read records & do something ... }
Map<String,A> ableMap = new HashMap<String,A>;
ableMap.put("willwork",new A());
processAble(as);
processAble(unableMap); // from the definition above
declaration of
Map<String,? extends Able> as;
means "any map, with String keys, and values being subtype of Able". So, for example, you can do following:
Map<String,? extends Able> as = new HashMap<String, SubSubAble>();
And now let's look at this example:
Map<String,? extends Able> as = new HashMap<String, SubSubAble>();
as.put("key", new A() );
If it were correct, you'll finish having HashMap with content {"key", new A()} - which is type-error!
Collection<?> is the supertype for all kinds of collection. It is not a collection that can hold any type. At least that was my misunderstanding of the whole concept.
We can use it where we don't care about the generic type, like in this example:
public static void print(Collection<?> aCollection) {
for (Object o:aCollection) {
System.out.println(o);
}
}
If we had chosen the signature instead:
public static void print(Collection<Object> aCollection)
we would have limited ourselves to collections of type Collection<Object> - in other words, such a method wouldn't accept a Collection<String> type value.
So a Collection<?> type is not a collection that can take any type. It only takes the unknown type. And as we don't know that type (its unknown ;) ), we can never add a value, because no type in java is a subclass of the unknown type.
If we add bounds (like <? extends Able>), the type is still unknown.
You're looking for a declaration of a map, whose values all implement the Able interface. The correct declaration is simply:
Map<String, Able> map;
Let's assume we have two types A and B that subclass Able and two additional maps
Map<String, A> aMap;
Map<String, B> bMap;
and want a, method that returns any map whose values implement the Able interface: then we use the wildcard:
public Map<String, ? extends Able> createAorBMap(boolean flag) {
return flag ? aMap: bMap;
}
(again with the constraint, that we can't add new key/value pairs to the map that is returned by this method).
You can't insert any object of any type in a collection declared using the wild card '?'
you can only insert “null”
Once you declare a collection as List, the compiler can't know that it's safe to add a SubAble.
What if an Collection<SubSubAble> had been assigned to Collection<Able>? That would be a valid assignment, but adding a SubAble would pollute the collection.
How can elements be added to a wildcard generic collection?
Related
I have a List<? extends MyClass> list and I want to add into this list objects whose class extends MyClass and objects which are instances of MyClass:
list.add(new ClassThatExtendsMyClass());
list.add(new MyClass());
but eclipse shows the build error:
The method add(capture#9-of ? extends MyClass) in the
type List is not
applicable for the arguments (MyClass)
How can I get around this?
Java keyword extends in generic type of reference is used to restrict actual generic type realization to be no less derived than the named type. Especially it can be a subclass. One should use it in case type is used to extract values and operate on them. You then use the interface of the base class not concerning the actual type (realization/implementation) of that class.
When you've got a specific class and need to pass (put) into collection, or other generic class object, the reference to point at that object should have super keyword, which restricts the actual object to be no more derived than the named type.
Code example below. Assume we have classes Base and Derived, where Derived extends Base, class Base have an interface method foo() and both have default constructor.
void service() {
List<Base> theList = new ArrayList<Base>();
produceObjects(theList);
consumeObjects(theList);
}
void produceObjects(List<? super Base> consumerList) {
consumerList.add(new Derived());
}
void consumeObjects(List<? extends Base> producerList) {
for (Base base : producerList) {
base.foo();
}
}
You can declare your reference as List<MyClass>.
You'll be able to add anything extending MyClass, including instances of MyClass.
This is not possible. List<? extends MyClass> list could actually point to a ArrayList<ClassThatExtendsMyClass>. Which can't hold instances of some other subclass of MyClass.
List<? extends Number> numbers = new ArrayList<Integer>();
numbers.add(Long.valueOf(2)); // not possible since 'Integer' array can't hold Longs
If you want to add things you should declare your variable 'list' as List<? super MyClass>. This will enable you to add any subclass of 'MyClass' into the list.
List<? super Number> numbers = new ArrayList<Number>();
numbers.add(Long.valueOf(2));
This is known as the 'get' and 'put' principle. If you want to 'get' stuff you need to have the List<? extends MyClass> syntax whilst if you want to 'put' stuff you need to have the List<? super MyClass> syntax. Ofcourse if you need to do both then you need to use List<MyClass> syntax.
Try this:
List<MyClass>
It should work
Define it this way:
List<MyClass> list
I'm new to these generic types. In the below code, I created a method that accepts a List of items that extends "String".
My Question? - When the list can be assigned with a new list that is , why can't a string "test" can be added...It gives me a compilation error.
public class Child {
public void takeList(List<? extends String> list){
list = new ArrayList<String>();
list.add("test");
}
}
Because it's not the runtime type that's relevant here. list is still of type List<? extends String>, you've just happened to assign it to a new ArrayList<String>(). Consider this:
list = rand() ? new ArrayList<String>() : new ArrayList<NotString>();
The compiler could not possibly tell if list.add("test") will be valid -- it only makes decisions based on the compile-time type of list.
Note that in reality nothing extends String, it's a final class.
There's a subtle difference. It takes a list that contains one type of thing (a thing that extends string). This list may be a subclass of String and therefore not be a String iyswim. See http://docs.oracle.com/javase/tutorial/java/generics/upperBounded.html Upper bounded wildcards.
If it was
public void takeList(List<? *super* String> list){
Then you could add strings to it, because the list is guaranteed to be able to accept Strings.
When you have a variable with a wildcard, and a method that takes the generic type parameter, Java cannot ensure type safety. It must disallow this call.
Consider a List<? extends Animal> for example. You may have assigned it List<Dog>, but the variable could be assigned a List<Squid>. You shouldn't be allowed to add a Dog to such a list.
To allow the add method to be called, remove the wildcard.
public void takeList(List<String> list){
Besides, String is final, so there really is no point to saying ? extends String.
this is from HeadFirst Java: ( page 575 )
This:
public <T extends Animal> void takeThing(ArrayList<T> list)
Does the same thing as this:
public void takeThing(ArrayList<? extends Animal> list)
So here is my question: if they are exactly same, why don't we write
public <? extends Animal> void takeThing(ArrayList<?> list)
or
public void takeThing(ArrayList<T extends Animal> list)
Also, when would it be useful to use a ? instead of a T in a method declaration ( as above ) with Generics, or for a Class declaration? What are the benefits?
The big difference between
public <T extends Animal> void takeThing(ArrayList<T> list)
and
public void takeThing(ArrayList<? extends Animal> list)
is that in the former method you can refer to "T" within the method as the concrete class that was given. In the second method you cannot do this.
Here a more complex example to illustrate this:
// here i can return the concrete type that was passed in
public <T extends Animal> Map<T, String> getNamesMap(ArrayList<T> list) {
Map<T, String> names = new HashMap<T, String>();
for (T animal : list) {
names.put(animal, animal.getName()); // I assume there is a getName() method
}
return names;
}
// here i have to use general Animal
public Map<Animal, String> getNamesMap(ArrayList<? extends Animal> list) {
Map<Animal, String> names = new HashMap<Animal, String>();
for (Animal animal : list) {
names.put(animal, animal.getName()); // I assume there is a getName() method
}
return names;
}
With the first method if you pass in an List of Cats you get a Map with Cat as key. The second method would always return a Map with general Animal key.
By the way this is not valid java syntax:
public <? extends Animal> void takeThing(ArrayList<?> list)
Using this form of generic method declaration you have to use a valid java identifier and not "?".
Edit:
The form "? extends Type" only applies to variable or parameter type declaration. Within a generic method declration it has to be "Identifier extends Type" as you are able to refer to the "Identifier" from within your method.
Wild cards are about co/contra variance of generics. I will try to make clear what this means by providing some examples.
Basically it is related to the fact that for types S and T, where S is a subtype of T, a generic type G<S> is not a valid subtype of G<T>
List<Number> someNumbers = new ArrayList<Long>(); // compile error
You can remedy this with wild cards
List<? extends Number> someNumbers = new ArrayList<Long>(); // this works
Please note, that you can not put anything into such a list
someNumbers.add(2L); //compile error
even (and more surprising for many developers):
List<? extends Long> someLongs = new ArrayList<Long>();
someLongs.add(2L); // compile error !!!
I think SO is not the right place to discuss that in detail. I will try to find some of the articles and papers that explain this in more detail.
Binding the type to a type parameter can be more powerful, depending on what the method is supposed to do. I'm not sure what takeThing is supposed to do, but imagine in general we have a method with one of these type signatures:
public <T extends Animal> void foo(ArrayList<T> list);
//or
public void foo(ArrayList<? extends Animal> list);
Here's a concrete example of something you can only do with the first type signature:
public <T extends Animal> void foo(ArrayList<T> list) {
list.add(list.remove(0)); // (cycle front element to the back)
}
In this case T is required to inform the type checker that the element being removed from the list is an OK element to add to the list.
You could not do this with a wildcard because, as the wildcard has not been bound to a type parameter, its context is not tracked (well, it is tracked, through "captures", but it's not available to leverage). You can get more information on this in another answer I've given: How do generics of generics work?
If you write ? extends T you say "anything that is a T or more specific". For example: a List<Shape> can have only Shapes in it, while a List<? extends Shape> can have Shapes, Circles, Rectangles, etc.
If you write ? super T you say "anything that is a T or more general". This is less often used, but has it's use cases. A typical example would be a callback: if you want to pass a Rectangle back to a callback, you can use Callback<? super Rectangle>, since a Callback<Shape> will be able to handle Rectangles as well.
Here's the relevant Wikipedia article.
If your takeThing method needs to add elements to the list parameter, the wildcard version will not compile.
The interesting case is when you are not adding to the list and both versions seem to compile and work.
In this case, you would write the wildcard version when you want to allow different type of animals in the list (more flexibility) and the parameter version when you require a fixed type of animal in the list: the T type.
For example the java.util.Collection declares:
interface Collection<E> {
...
public boolean containsAll(Collection<?> c);
...
}
And suppose you have the following code:
Collection<Object> c = Arrays.<Object>asList(1, 2);
Collection<Integer> i = Arrays.<Integer>asList(1, 2, 3);
i.containsAll(c); //compiles and return true as expected
If the java.util.Collection would be:
interface Collection<E> {
...
public boolean containsAll(Collection<E> c);
...
}
The above test code would not compile and the flexibility of the Collection API would be reduced.
It worth noting that the latter definition of containsAll has the advantage of catching more errors at compile time, for example:
Collection<String> c = Arrays.asList("1", "2");
Collection<Integer> i = Arrays.asList(1, 2, 3);
i.containsAll(c); //does not compile, the integer collection can't contain strings
But misses the valid test with a Collection<Object> c = Arrays.<Object>asList(1, 2);
Java Generics Wildcards usage is governed by the GET-PUT Principle (Which is also known as the IN-OUT principle). This states that:
Use an "extends" wildcard when you only get values out of a structure, Use a "super" wildcard when you only put values into a structure, and do not use wildcards when you do both. This does not apply to a method's return type. Do not use a wildcard as a return type. See example below:
public static<T> void copyContainerDataValues(Container<? extends T> source, Container<? super T> destinationtion){
destination.put(source.get());
}
The basic thing I want to achieve is to map a list of references List<Ref<Thing>> to a list of the actual objects, but given by the superclass List<SuperThing>. In this example, Thing extends SuperThing and Ref<Thing> has a method public Thing get() to get the referenced object.
The method that I assumed valid:
public <T> List<T> refsToObjects(List<Ref<? extends T>> list) {
List<T> result = new ArrayList<T>();
for(Ref<? extends T> ref : list) {
result.add(ref.get());
}
return result;
}
But when I try to use it
List<Ref<Thing>> refs;
List<SuperThing> objectList = refsToObjects(refs);
I get this error message: The method refsToObjects(List<Ref<? extends T>>) is not applicable for the arguments (List<Ref<Thing>>)
I did not actively use the ? extends T wildcard structure before, but what am I doing wrong?
It works, if you specify the "extended" parameter also as generic parameter:
public <T, S extends T> List<T> refsToObjects(List<Ref<S>> list) {
List<T> result = new ArrayList<T>();
for(Ref<S> ref : list) {
result.add(ref.get());
}
return result;
}
Declare your method as taking List<? extends Ref<? extends T>> instead:
public <T> List<T> refsToObjects(List<? extends Ref<? extends T>> list) { ... }
Nothing should have to change within the body.
EDIT: type inference still seems to fail at the call site using this solution. It only works with a call like this.<SuperThing>refsToObjects(refs). So wrm's solution using an additional type parameter is preferable if you can expect this kind of usage.
As I can see it, there are two errors in your code. The first is to believe that the type List<Ref<? extends Thing>> is a supertype for List<Ref<Thing>>. If we create a subclass of Thing like DerivedThing, we cannot add an instance of Ref<DerivedThing> to a list of List<Ref<Thing>>:
List<Ref<Thing>> refs = new ArrayList<Ref<Thing>>();
refs.add(new Ref<Thing>()); // OK.
refs.add(new Ref<DerivedThing>()); // Error!
However, if we replace this with List<Ref<? extends Thing>> then there is no more problem with the class DerivedThing:
List<Ref<? extends Thing>> refs = new ArrayList<Ref<? extends Thing>>();
refs.add(new Ref<Thing>()); // Still OK.
refs.add(new Ref<DerivedThing>()); // Now OK!
Therefore, if the compilator was to allow to pass of a value of List<Ref<? extends Thing>> to a function taking List<Ref<? extends Thing>> as its argument, this would allow the function to add some invalid item to the list.
The second error is to think that the base type (or erasure type) of <? extends Thing> is SuperThing instead of remaining Thing. Here, <? extends Thing> designates the collection of type composed of Thing and its derived classes and not the collection of SuperThing and its derived classes. Therefore, we could write:
List<Ref<? extends Thing>> refs = new ArrayList<Ref<? extends Thing>>();
refs.add(new Ref<Thing>());
List<Thing> objectList = refsToObjects(refs);
or, with SuperThing as the erasure type:
List<Ref<? extends SuperThing>> refs = new ArrayList<Ref<? extends SuperThing>>();
refs.add(new Ref<Thing>());
List<SuperThing> objectList = refsToObjects(refs);
but not a combination of both because List<SuperThing> is not a superclass for List<Thing>. Notice that we can stil add a Ref<Thing> to a List<Ref<? extends SuperThing>>. Therefore, use of one of the above solution or use the wrm's solution if you want to keep List<Ref<Thing>> as your starting point.
Personally, I would prefer to use polymorphism at its fullest extend and always reference everything from a SuperThing; even when creating Thing or Ref<Thing> objects. For example, if we add a parameter of type T to the constructor of Ref():
List<Ref<SuperThing>> refs = new ArrayList<Ref<SuperThing>>();
refs.add(new Ref<SuperThing>(new Thing()));
List<SuperThing> objectList = refsToObjects(refs);
Note that we are now passing an object of type Thing to a reference of type SuperThing in the constructor of Ref(). By using the superclass of the hierarchy as the reference for all the derived objects, all the coding become much more simpler. OOP works very well and very easily when you choose to see all the objects mostly only through their superclass and this extends to the use of generic.
The types must match exactly, so:
List<Ref<? extends Thing>> refs = new ArrayList<Ref<? extends Thing>>();
List<SuperThing> objectList = refsToObjects(refs);
should work.
It will also work if you do something like this:
List<Ref<Thing>> refs;
List<SuperThing> objectList = this.<Thing>refsToObjects(refs);
What is happening is that the method expects something which extends T. but you never define T. The one explained by #wrm defines it in the method.
I took a look on questions q1, q2, q3, but they don't cover exactly my question.
Note that ArrayList<A> and ArrayList<? extends A> are to be used for declaring a variable or a parameter (not for creating a new generic class).
Are both expressions equivalent when declaring an object attribute (case 1)?:
class Foo {
private ArrayList<A> aList; // == ArrayList<? extends A> aList;
}
EDIT: Are both expressions equivalent from the point of view of what
kind of objects are allowed to be added to aList?, but different
in the same sense as the following case?
but they are different when used in a parameter declaration (case 2)?:
void methodFoo(ArrayList<A> al) != void methodFoo(ArrayList<? extends A> al)
because the first one only allows to be passed ArrayList objects
while the second would be like "more permissive" allowing to be sent
ArrayList<A1> and ArrayList<A2> (as long as A1 and A2 extends A)?
If this is right, is there any other scenario where the two expressions are
effectively different?
Thanks,
Let's have a look at some practical examples. Say, you have:
List<Number> list;
This means that whatever is assigned to this variable or field takes Number and outputs Number, so you always know what to expect. Integer can be added to this list since Integer extends Number. However, you can't assign, say, ArrayList<Long> to this list.
But consider this case:
List<? extends Number> list;
This one says: hey, that's a list of something that extends Number, but no one knows what exacty. What does this mean? This means that you can assign, for example, ArrayList<Long> to this list, which you couldn't in the first case. You still know that whatever this list outputs will be a Number, but you can't put an Integer in it anymore.
There is also an opposite case:
List<? super Number> list;
By printing that you say: that's a list of Number or its superclasses. This is where everything becomes vice-versa. The list can now refer to ArrayList<Object> and ArrayList<Number>. Now we don't know what this list will output. Will it be a Number? Will it be an Object? But now we know that we could put a Number in this list as well as any subclass of Number like Integer or Long.
There is a rule, by the way, which says producer extends, consumer super (PECS for short). If you need the list to output the values, it is a producer, this is the second case. If you need the list to accept values, it is a consumer, this is the third case. If you need both, don't use wildcards (that's the first case).
I hope this clears up matters.
This will explain the difference:
public class GenericsTest {
private ArrayList<A> la;
private ArrayList<? extends A> lexta;
void doListA(ArrayList<A> la) {}
void doListExtA(ArrayList<? extends A> lexta) {}
void tester() {
la = new ArrayList<SubA>(); // Compiler error: Type mismatch
doListA(new ArrayList<SubA>()); // Compiler error: Type mismatch
lexta = new ArrayList<SubA>();
doListExtA(new ArrayList<SubA>());
}
static class A {}
static class SubA extends A {}
}
As you see, calling a method and assigning a variable/instance field have the same rules. Look at the method call as an assignment of your argument to its declared parameter.
ArrayList<A> means a specific class A, where as ArrayList<? extends A> means class A or any class which extands A (Sub class of A) this make it more generic
Using private ArrayList<A> aList; as a variable declaration is not really equivalent to using the wildcard private ArrayList<? extends A> aList;
The wildcarded version will allow you to assign any ArrayLists of types that extend A and A itself but will refuse to add elements to the list as it cannot decide if it is type safe. With ArrayList<A> on the other hand you can only assign ArrayLists (or extensions of ArrayList) of type A and you can then add A elements and any elements extending A to it.
FYI: you should prefer using a more abstract type for declaring your variables/parameters like List<A> or Collection<A>.
The main difference is that if the generic form is used as an argument or return type in a method in a base class (or interface), it allows a greater range of type signatures to count as overriding instead of overloading.
Function override-overload in Java
For example, the following code is legal (in Java 7):
interface A
{
List<? extends Number> getSomeNumbers();
}
class B implements A
{
#Override
public ArrayList<Integer> getSomeNumbers()
{
return new ArrayList<>();
}
}
Difference between Enumeration<? extends ZipEntry> and Enumeration<ZipEntry>?
All of this means that sometimes you can write come code that requires less casts when someone else is using it. Which should not only reducing the amout of typing they have to do, but also eliminate possible failures.
Of course, the problem with Java generics is that they were introduced in a way that was constrained by backwards compatibility. So not everything works that you might think should, and the details get pretty hairy as to what exactly works and what doesn't.
http://www.angelikalanger.com/GenericsFAQ/FAQSections/TechnicalDetails.html#FAQ812
It is hard to grasp at first, but inheritance doesn't apply with generics, ie if B extends A, List<B> is not a "subclass" of (can not be assigned to) List<A>. Further, List<? extends A> is not a "subclass" of (can not be assigned to) List<A>.