4

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.

donnadulcinea
  • 1,854
  • 2
  • 25
  • 37
  • Why is the first line `Myclass` and not `MyClass`? – user202729 Aug 27 '18 at 04:10
  • If all you want to do is add instances of any child of MyClass to items, then the `? extends` bit is not really needed: a List will accept any instances that are of type MyClass or any class inherited from MyClass... – moilejter Aug 27 '18 at 04:19
  • I think the notation ` extends MyClass>` is read as "some one class that extends MyClass, or MyClass itself" - but there's not enough information in that type for the compiler to know _which_ subtype of MyClass you meant to use... – moilejter Aug 27 '18 at 04:21

3 Answers3

6

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
xingbin
  • 27,410
  • 9
  • 53
  • 103
4

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.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157
1

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.

Ashishkumar Singh
  • 3,580
  • 1
  • 23
  • 41
  • WOW! That's IT! Every other approach I tried has its shortcomings: with `List extends MyClass>` I can't add anything. with `List` I need to cast all the elements on the getter, and I can in fact not use any setter. This way I just need to cast the elements on get, thus, can write, i.e., `List super MyClass> _items = getItems(); if (_items == null) _items = new LinkedList(); MyClass item = (MyClass)_items.get(0);` and also `items.add(new MyClass());` THANKS. – donnadulcinea Aug 27 '18 at 04:49
  • Glad to help :) – Ashishkumar Singh Aug 27 '18 at 04:52