Adding data to the general? extends the list

Possible duplicate:
Java ArrayList? extends the interface

There is this code:

public static class B1 {} public static class B2 extends B1 {} public void fun() { List<? extends B1> l3 = new ArrayList<>(); l3.add(new B2()); } 

Compilation Error:

 java: no suitable method found for add(Main.B2) method java.util.List.add(int,capture#1 of ? extends Main.B1) is not applicable (actual and formal argument lists differ in length) method java.util.List.add(capture#1 of ? extends Main.B1) is not applicable (actual argument Main.B2 cannot be converted to capture#1 of ? extends Main.B1 by method invocation conversion) 

I guess that ? extends B1 ? extends B1 means any type that extends from B1. It seems that type B2 extends from B1, so why can't an object of this type be added to the list and how to make it so that it can be added?

+4
source share
5 answers

I think what ? extends B1 ? extends B1 means any type that extends from B1.

No. This means "a specific but unknown type that extends from B1." Since the specific type is unknown, the compiler cannot ensure its execution, so operations like add do not work. *

See the tutorial on patterns .

How to make it possible to add?

In principle, do not use wildcards for this. You probably want this:

 List<B1> l3 = new ArrayList<B1>(); 


* Well, they work, but only for null (and a few other cases, see @Marko's comment below).
+7
source

? extends B1 ? extends B1 means: some type that is or extends B1, but we do not know which one. Thus, the list may be List<B1> , or List<B2> , or List<B3> (assuming B3 also extends B1). And you do not want to add B2 to List<B3> , so the compiler forbids it.

You probably need List<B1> .

+2
source

So you need a list of elements like B1 , I think. Each child of B1 can be stored in list B1 as follows:

 public static class B1 {} public static class B2 extends B1 {} public void fun() { List<B1> l3 = new ArrayList<>(); l3.add(new B2()); } 
+1
source

Make B1 and B2 to implement the same interface as B (maybe even empty), and then declare a list <B> instead. You can add and remove members without problems.

The main problem with direct inheritance can be summarized as:

 class B1 {}; class B2 extends B1{}; ArrayList<B2> list; addMembers(list); // Error here void addMembers(ArrayList<B1> list) { list.add(new B1()); } 

Here we declare list B2 and pass it as a parameter to the method that list B1 expects. Since every B2 is also B1, it is kind of intuitive that this should work. But now, in this method, it is becoming legal to add also B1 to the transferred list. The collection will be broken when the method returns containing member B1, which is not allowed by the declaration.

To prevent this, the compiler will not allow addMembers to be addMembers with a "compatible inherited type" collection. I found this to be a rather unpleasant limitation that can be easily circumvented using the interfaces as suggested. It is quite difficult to get this right also with the help of wildcards. Do you think you can just write ? extends B1 ? extends B1 ?

 void test() { ArrayList<? extends B1> list = new ArrayList(); list.add(new B1()); // Error here list.add(new B2()); // Error here test2(list); } void test2(ArrayList<? extends B1> list) { list.add(new B1()); // Error here, the collection is read only. } 

That I say, these wildcards are not worth the pain. And you can also write ArrayList<? extends java.lang.Object> ArrayList<? extends java.lang.Object> or even ArrayList< ? > ArrayList< ? > will not be useful, such ads still do read-only collection.

Therefore, I would say better

 interface B {}; class B1 implements B {}; class B2 extends B1 implements B {}; ArrayList<B> list = new ArrayList<B>(); list.add(new B1()); list.add(new B2()); test2(list); void test2(ArrayList<B> list) { list.add(new B1()); } 
0
source

Since this question has already been given, but I would also like to add something valuable here. As everyone suggested doing

 List<B1> l3 = new ArrayList<B1>(); 

Right. But in order to understand the logic, you should also try below, which does not give any error.

 public void fun() { List<? extends B1> l3 = new ArrayList<>(); List list1= new ArrayList(); list1.add(Element1 extending B1); list1.add(Element2 extending B1); l3=list1; } or you can also try public void fun() { List<? extends B1> l3 = new ArrayList<>(); List<B1> list1= new ArrayList(); list1.add(B1 element); l3=list1; } 

So your statement below is true, but for assignment not for the add method. In a nutshell, for an add operation, it must be a truly unknown type (e.g. null), but

? extends B1 means any type that extends from B1.

0
source

All Articles