What is the purpose of "? extends A"? [duplicate] - java

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.

Related

Java cannot call addAll() to add arraylist of type subclass to an arraylist of type <? extends baseClass> [duplicate]

This question already has answers here:
What is PECS (Producer Extends Consumer Super)?
(16 answers)
Closed 3 years ago.
I have two classes, a superclass, and a child class inheriting the superclass. I want to combine two array lists into one. The two arraylists have different types. One is a superclass list the other is a subclass.
These are my three lists:
public ArrayList<subClass> list1;
public ArrayList<superClass> list2;
public ArrayList<? extends superClass> combined; // so this accepts all subclasses as well
I am then trying to accomplish the below:
combined.addAll(list1);
combined.addAll(list2);
The compiler is saying:
addAll in arrayList cannot be applied to list1
addAll in arrayList cannot be applied to list2
but: combined = list1; gives no error. With the equals sign though I cannot combine the two lists.
How can I achieve this?
public ArrayList<? extends superClass> combined
Doesn't mean "this accepts all subclasses as well". It means you can assign to that variable an ArrayList<superClass> or an ArrayList<subClass> or an ArrayList<someOtherSubClass>, etc...
Therefore you can't assign to it the elements of list1 or list2, since the compiler doesn't know which ArrayList<? extends superClass> will be assigned to that variable).
For example, if you initialized that variable with:
public ArrayList<? extends superClass> combined = new ArrayList<subClass2>();
You shouldn't be able to add to that List instances of type subClass.
You could use:
public ArrayList<superClass> combined
instead. Now you can add to that ArrayList all elements of type superClass or any sub-class of it.

How may I add `MyClass` to `List<? extends MyClass>` [duplicate]

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.

If you're trying to have list with various child classes of a single parent class, how would you do it?

Should you use
List<ParentClass> foo = new ArrayList<ParentClass>
foo.add(ChildClassObject)
or
List<? extends ParentClass> bar - new ArrayList<ParentClass>
bar.add(ChildClassObject)
Also, could someone explain more to me the latter parameterization of List?
Use the first approach. The second doesn't allow you to add any element. This is because the second approach uses an unknown type that extends ParentClass and cannot assure that the elements to be stored are from this type.
More info:
Java Generic with ArrayList <? extends A> add element
List<? extends ParentClass> is a list of some specific subtype of ParentClass. Since, it's not know what exact specific subtype it is, the compiler won't let you add any object to it.
For starters, it's easy to mistake it with any subtype of ParentClass and wonder why they can't add the instances of the subtypes.
For instance, suppose you have a following class hierarchy -
class P { }
class A extends P { }
class B extends P { }
Now if you declare a a list as follows -
List<? extends P> l = ...;
it means l is a list of some specific subtype of P, which could be either A or B (or even P itself), but the compiler doesn't know exactly which one. So, you can't add anything to it, because the chance is that you could be adding an instance of B to a list of As creating some heap pollution.
You would declare such a list when you are only interested in reading the elements of list as P's instances.

<T extends AnInterface> vs <? extends AnInterface>

I am a little confused with something.
I have a class where its not a collection, but it does refer to generic objects:
public class XClass<E extends AnInterface>{
E instanceobject;
public void add(E toAdd){}
}
public interface AnInterface{}
public class A implements AnInterface{}
public class B implements AnInterface{}
I believe I read somewhere that <? extends AnInterface> is to be used (when declaring an instance of XClass) if you want multiple subtype-types in the generic object at the same time, whereas <T extends AnInterface> would only allow you to have a single type of subtype in the generic class at once?
However, I can just use:
XClass<AnInterface> xc = new XClass<AnInterface>();
A a = new A();
B b = new B();
xc.add(a);
xc.add(b);
and this way I can pass in multiple subtypes of Supertype to the generic class......
I am not seeing the purpose of using "?" and is there anything wrong with using the Interface as the generic parameter?
The reason why you can add objects of both type A and B is due to the fact that you parametized your XClass with the interface, so there is nothing wrong with adding two different classes that implement that interface.
If, on the other hand, you had defined XClass as:
XClass<A> xc = new XClass<A>();
then the expression xc.add(b); would give a compilation error, since all the objects added must have the same type as was declared, in this case, A.
If you declare you xc as, for instance:
XClass<? extends AnInterface> xc = new XClass<AnInterface>();
Then it's not legal anymore to add a or b, since the only thing we know is that xc is of some unknown but fixed subtype of AnInterface, and there is no way to know if that unknown type is A or B or anything else.
But let's say you're writing a method to accept a XClass type that you can iterate over the elements that were added before. Your only restriction (for the sake of the example), is that the items extend AnInterface, you don't care what the actual type is.
You can declare this method like:
public static void dummyMethod(XClass<? extends AnInterface> dummy){
//do stuff here, all the elements extend (implement in this case), AnInterface, go wild.
}
And now you can pass into this method anything like XClass<A>, XClass<B> or XClass<AnInterface>, and it will all be valid.
Keep in mind that you can't add to the object you pass, for the same reason above. We don't know what the unknown type is!
public static void dummyMethod(XClass<? extends AnInterface> dummy){
//do stuff here, all the elements extend (implement in this case), AnInterface, go wild.
dummy.add(new A()); //you can't do this, we have no idea what type ? stand for in this case
}
You can use E if you want to have an instance of XClass to use only one subclass of AnInterface and no other Classes implementing AnInterface that do not extend / implement E.
For example given
public class ClassOne implements AnInterface {} and public class ClassTwo implements AnInterface {}
If you were to use
public class XClass<E extends AnInterface> and <ClassOne>XClass xc = new <ClassOne>XClass() then you can only use an object of ClassOne in your add method not one of ClassTwo. Using ? would allow you to pass in any class implementing AnInterface, either ClassOne or ClassTwo.
Using Identifier E means "For this object I want to use type E and any subclasses", using ? means "I want to use any type that matches the the expression"
In your example you need type erasure in the method "add", so you should't use wildcards in your class.
Wildcards are only to be used when you do not need type erasure (i.e. you don't care about the type as long as it is a subclass of..) and also when you will need to subtype the generics itself.
The wildcard simply means that it will be some class that meets that criteria. So ? extends AnInterface means it will be one (and only one) class that extends AnInterface.
So it could be:
XClass<Impl1>
XClass<Impl2>
etc...
However, at runtime, you don't know what that class will be. For this reason calling methods which take the actual type as a parameter is inherently unsafe, since it's impossible for the compiler to know if the parameter is appropriate for the actual instantiated instance.
Take lists as an example. Something might be declared like this:
List<? extends Number> list = new ArrayList<Integer>();
What would happen if you try to do either of these:
list.add(new Double(0));
list.add((Number) new Long(1L));
It would not compile, because the generic parameter type is unknown at compile time. So the compiler can't tell if Double or Number would be appropriate to pass to the actual instance (in this case ArrayList<Integer>). This is when you get the infamous capture-of compile error.
This, however is permissible, since you know for certain at compile time that the list can take any instance of Number (which includes subclasses).
List<Number> list = new ArrayList<Number>();
list.add(new Double(0));
list.add((Number) new Long(1L));

Passing List<Subclass> to method expecting List<SuperClass>

I have a method that is expecting a List<SuperClass> as argument:
public void myMethod(List<SuperClass> list) {}
I want to call that method with a List<Subclass> something like:
List<SubClass> subList = new ArrayList<>();
// ...
myMethod(subList); // Got an argument mismatch error on this line.
Shouldn't I be able to do this when SubClass extends SuperClass?
No, generics don't work like that. What you could do is define your method as MyMethod(List<? extends SuperClass> list) (by convention it should be named myMethod(...) btw).
The problem with List<SuperClass> vs. List<SubClass> is that you could add new elements to such lists whereas the compiler wouldn't allow you to add something to a List<? extends SuperClass> - and this has a reason:
Consider the following:
class A {}
class B extends A {}
class C extends A {}
If you now have a List<A> you could add instances of A, B and C. However, if you pass a List<B> to a method as a List<? extends A> parameter, the compiler doesn't know whether it is allowed to add instances of A or C to that list (it wouldn't be allowed, but in case you'd pass a List<A> it would be). Thus the compiler restricts you not to do so.
Defining a parameter as List<A> tells the compiler that is is ok to put instances of all three classes to that list. Now if you would be allowed to pass a List<B> as such a parameter you could end up with a List<B> that contains instances of A and/or C. And this is clearly not what you want and could result in runtime bugs that should be prevented at compile time already - by using generics. That's why your approach doesn't work.
Worth noting, you can also create the list of your superClass from a list of subClass as such:
myMethod(new ArrayList<SuperClass>(list));

Categories

Resources