This question already has answers here:
What is PECS (Producer Extends Consumer Super)?
(16 answers)
Method in the type Map<String,capture#1-of ? extends Object> is not applicable
(1 answer)
Closed 4 years ago.
I have a Java Class that contains subitems of Objects that extend MyClass.
class MyClass {
List<? extends MyClass> items;
[...]
For some reason I can't insert MyClass items to this list. I don't Understand why, and how I may bypass this issue. For example:
void foo(){
items = new LinkedList<MyClass>(); // This is OK
items.add(new MyClass()); // Not allowed... why?
}
The compiler says "The method add(capture#1-of ? extends MyClass) in the type List is not applicable for the arguments (MyClass)"
I really don't understand how to bypass this issue, and why the compiler should accept only a type which necessarely extends MyClass.
Note: why am I in the need to use this approach? Because I need to allow extension of MyClass to have list of subitems.
List<? extends MyClass> items means the type parameter is unknown type which is assignable to MyClass.
For example, it could be a List of MySubClass:
public MySubClass extends MyClass{}
List<? extends MyClass> items = new ArrayList<MySubClass>();
Now consider you have MyAnotherSubClass which extends from MyClass too:
public MyAnotherSubClass extends MyClass{}
MyClass item = new MyAnotherSubClass(); // refer it using MyClass
Obviously, List<MySubClass> should not be allowed to contain MyAnotherSubClass:
items.add(item); // compile error
The declaration
List<? extends MyClass> items;
says that items is a List whose type parameter is not exactly known, but is either MyClass or a subclass.
Re-read that, carefully. It explains why it is not type-safe to add anything to such a List: its type parameter is unknown. If it happens to be MySubClass1, then adding a MyClass or a MySubClass2 is incorrect. If it happens to be MySubClass2, then adding a MySubClass1 is incorrect. There is no type at all that can safely be added.
If you want a List to which you can add objects of type MyClass and also objects of any subclass of MyClass, then you probably are looking simply for List<MyClass>.
Technically, a List<? super MyClass> would also serve that specific purpose, but you would have the opposite problem with that: it would not be type safe to assume the list elements to be any type more specific than Object.
Using extends you can only get from the collection. You cannot put into it. You can do that using super.
So, in your case, if you use - List<? super MyClass> items; you will not get any compilation/runtime error.
Though super allows to both get and put, the return type during getting is ? super T.
Related
I'm trying to implement my own Adapter that extends SimpleAdapter. But one of the parameters of the SimpleAdapter's constructor needs a List<? extends Map<String, ?>>. How can I put such values inside that parameter?
I have tried creating my own class that extends Map but as it turns out, Map is an interface and should instead be implemented. So I really haven't moved on much with this problem.
E.g. a List<Map<String, String>> would be assignment compatible
with List<? extends Map<String, ?>>.
Any subtype of List is allowed.
The first ? means that any subtype of Map is allowed.
The second ? means that any value type is allowed.
So e.g. a LinkedList<TreeMap<String, Foo>> would also work.
I have the following member in my class:
List<? extends SomeObject> list;
When I try to do:
list.add(list.get(0));
I get:
Test.java:7: error: no suitable method found for add(CAP#1)
list.add(list.get(0));
^
method Collection.add(CAP#2) is not applicable
(argument mismatch; Object cannot be converted to CAP#2)
method List.add(CAP#2) is not applicable
(argument mismatch; Object cannot be converted to CAP#2)
where CAP#1,CAP#2 are fresh type-variables:
CAP#1 extends Object from capture of ? extends Object
CAP#2 extends Object from capture of ? extends Object
My question is twofold:
Why doesn't it compile? Why can't I pass get()'s result to add()?
And how can I achieve this in another way without resorting to casting?
I understand that in a method with <T extends SomeObject> I can't just say:
T someObject = list.get(0);
list.add(someObject);
since my T could be another extension than the ? extension.
I also understand I can't say:
List<? extends SomeObject> list1;
List<? extends SomeObject> list2;
list1.add(list2.get(0));
But since the add and the get should work with the same generic type in list.add(list.get(0)) I don't understand why the compiler doesn't accept it.
What I really need is
[something of type T where T is whatever was used to instantiate list] someObject = list.get(0);
list.add(someObject);
so that I can later
list.add(someObject);
I don't think I should have to template my whole class to achieve this, should I?
class MyClass<T extends SomeObject> {
List<T> list;
and then later a method with
T someObject = list.get(0);
of course works, but screws other parts of my code.
So the first question is why doesn't this work, second question is what's the best workaround?
My question is twofold, why can't I do:
list.add(list.get(0));
Because the compiler isn't smart enough to know that you're adding something from list back into list. The compiler doesn't consider list.get(0) to have anything to do with list once it is evaluated: it's just "some expression" of type ? extends SomeObject.
To solve this, add a method with its own type variable:
private <T> void addFirst(List<T> list) {
list.add(list.get(0));
}
and replace the original list.add(list.get(0)); with an invocation of this:
addFirst(list);
This only defines a type variable on the method, and does not need to be visible outside the class, so you don't need a class-level type variable.
It's perhaps worth pointing out this is analogous to the Collections.swap method: that's using set rather than add, but, from a generics point of view, it's the same thing:
#SuppressWarnings({"rawtypes", "unchecked"})
public static void swap(List<?> list, int i, int j) {
// instead of using a raw type here, it's possible to capture
// the wildcard but it will require a call to a supplementary
// private method
final List l = list;
l.set(i, l.set(j, l.get(i)));
}
This takes an approach which is technically type-safe, and does avoid casts; but it's a bit gross, because it uses raw types.
I would imagine that it is only like this for backwards-compatibility reasons. Given a chance to write it again, you could just define a type variable as in the addFirst method above.
When use wildcards, we should follow The Get and Put Principle which introduced in Java Generics and Collections:
The Get and Put Principle: 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 don’t use
a wildcard when you both get and put.
In your case, don't use a wildcard as you both get element from list and put element to list.
This question already has answers here:
When to use wildcards in Java Generics?
(6 answers)
Closed 8 years ago.
public <? extends Animal> void takeThing(ArrayList<?> list)
public <T extends Animal> void takeThing(ArrayList<T> list)
Why this statement is wrong? I mean why the ? can't be used in the front? But T can. What is the difference?
Possible duplicate "When to use wildcards in Java Generics?"
Here is an answer for this question.But I don't get what this mean.
"if you say void then there is no return type. if you specify then there is a return type. i didn't know that you can specify to have return type or no return type."
Writing <T extends Animal> binds the type name T, so that it can be referred to later in the definition (including in the parameter list).
If you wrote <? extends Animal>, then you did not name the type. Therefore, you cannot refer to it later. You can't refer to it as ? later because that could be ambiguous (what if you had two type parameters?).
Java forbids you from writing public <?> ... because such a declaration is useless (the type parameter is not named so it cannot be used).
public void takeThing(ArrayList<? extends Animal> list)
means "do something with a list of any subclass of Animal".
public <T extends Animal> void takeThing(ArrayList<T> list)
means "do something with a list of some particular subclass (A.K.A. T) of Animal".
If I call list.get() on the first method, all I know about the returned type is that it extends Animal. On the second method, if I had another instance of List<T>, I know that whatever type T is, both lists would accept the same type.
To take it even further, if I say
Animal animal = list.get(0);
I can no longer say
list.add(animal);
even on the very same list, because we don't have a reference to the generic subtype. If however, I declare a List<T> where <T extends Animal>, I can now say
T animal = list.get(0);
list.add(animal);
because we know that list expects elements of type T.
This question already has answers here:
Main intention or Purpose of Wildcard notation' ? extends T'
(2 answers)
Closed 8 years ago.
If I have a list like this:
static ArrayList<? extends A> list = new ArrayList<A>();
What is the point of ? extends A? Does it mean that I am making a list of only subclasses that MUST inherit from A?
Normally I do it like this:
static ArrayList<A> list = new ArrayList<A>();
extends keyword means that the class on the left of this keyword would be using all the methods and properties from the class that is one the right side. ? wouldn't be there. Some name would be. A name of a class.
static ArrayList<? extends A> list = new ArrayList<A>();
In the above code, you're making a new ArrayList object which uses (implements/extends) the Class A for its methods and properties but is not in real A.
static ArrayList<A> list = new ArrayList<A>();
Whereas in the second code that you usually use, you're actually creating an Object which uses class A in real.
In Java we call it inheritance where one class inherits all the properties and functions of the other class.
http://docs.oracle.com/javase/tutorial/java/IandI/subclasses.html
From Java Docs:
The upper bounded wildcard, <? extends Foo>, where Foo is any type, matches Foo and any subtype of Foo.
So, answering the question "Does it mean that I am making a list of only subclasses that MUST inherit from A?"
It means that you are making a list of objects which types are A or inherit from A.
Edit:
One difference is that in the second code
ArrayList<A> list = new ArrayList<A>();
you will be able to refer to the type A anywhere in the code.
Are the both same?
ParentClass object=new ChildClass();
ParentClass object = (ParentClass) new ChildClass();
If I want to create a map which maps a string to Children Objects like
"dog"->childA;
"cat"->childB
How should I declare the Map?
Map<String,Parent>
or
Mpa<String,T extends Parent>
I am not sure if the second one is right or not but I read it somewhere
Are the both same?
Casting is unnecessary in the 2nd assignment. The first one is valid assignment. You can assign a child class object to super class reference.
How should I declare the Map?
You should declare it the first way. A Map<String, Parent> will be capable of holding instances of Parent or any of it's subclasses.
As for your 2nd declaration:
Map<String, T extends Parent> // This won't compile
this is not the correct way to specify bound in type parameter while declaring map. You can't use bounded type parameter there. You should either use a wildcard bound, or just a type parameter - Map<String, T>, with bounds for T being declared where you declare that type (perhaps in the generic class where you declare the map). So, you can use <? extends Parent>. The issue with declaring map this way is that, you won't be able to add anything into it, accept null.
Related Post:
What is PECS (Producer Extends Consumer Super)?
Reference:
Angelika Langer - Java Generics FAQs
What is the difference between a wildcard bound and a type parameter bound?
The cast and non-cast are indeed the same.
For the generic, if you declare it with <String, ? extends Parent>, you won;t be able to add things to the list due to the fact that if it was declared <String, Child> parents couldn't be added. If NewChild was created by another dev, then we can;t know if Parent, Child, or NewChild is used and writes would not be allowed.
The first two are identical in effect. Casting is unnecessary.
If you want the map to contain a mixture of child classes, you need to declare
Map<String,Parent>
If you declare
Map<String,T extends Parent>
it declares a map from String to one particular child class of type T. The type parameter will need to be specified elsewhere (as a type parameter to the containing class or to an enclosing method). Note that you cannot instantiate a Map of an unbound type. Thus, for instance:
Map<String,? extends Parent> = new HashMap<String, ? extends Parent>();
generates a compiler error. The best you could do is:
Map<String,? extends Parent> = new HashMap<String, Parent>();
in which case you might as well stick with
Map<String,Parent> = new HashMap<String, Parent>();