Can someone clarify covariant return types in Java (6)?

I think I'm asking about covariant return types. I have generated code that I am trying to extend and use. Suppose I have the following two classes:

public class SuperParent { public List<SuperChild> getList() { return new ArrayList<SuperChild>(); } } public class SuperChild { } 

Now I want to get new classes from them:

 public class SubParent extends SuperParent { public List<SubChild> getList() { return new ArrayList<SubChild>(); } } public class SubChild extends SuperChild { } 

The problem is that I cannot override the getList () method because the return type does not match, despite the fact that both classes are extended in the same direction. Can someone explain?

+4
source share
5 answers

Your co-variant understanding is correct, but usasge is not. List<SubChild> does not match List<SuperChild>

Consider this, List<Animals> does not match List<Dogs> , and everything can go horribly wrong if it was allowed. A Dog is Animal , but if it was allowed to assign, as shown below:

 List<Dogs> dogs = new ArrayList<Dogs>(); List<Animals> animals = dogs; //not allowed. 

what will happen when you add a cat?

 animals.add(new Cat()); 

and

 Dog dog = dogs.get(0); //fail 

Therefore, it is not allowed.

As many others have said, use List<? extends SuperChild> List<? extends SuperChild> as a return type to solve your problem.

EDIT To your comment above, if you don't have control over the superclass, I'm afraid you can't do anything.

+5
source

The problem is that with generics, List<SuperChild> and List<SubChild> are not compatible, as if you would call getList() on a SubParent instance, but through the SuperParent interface, you would get a return value of type List<SuperChild> . This will allow you to add other SuperChild instances, even if the list is allowed to contain SubChild instances (according to the return type defined in SubParent ).

To do this compilation, change the return type to List<? extends SuperChild> List<? extends SuperChild> , i.e.

 public class SuperParent { public List<? extends SuperChild> getList() { return new ArrayList<SuperChild>(); } } 

This will allow you to return lists of subtypes, but will not allow you to add items to the list returned by the super type (i.e. you cannot add items to the List<? extends SuperChild> .

+3
source

List<SubChild> not a subclass of List<SuperChild>

There is no covariance in java generics.

So, when you try to compose the return type, it is actually a different type, and java does not allow you to change it completely [since it will not be safe].

Your getList() method in SubParent should return List<SuperChild> [or ArrayList<SuperChild> , ...] to solve this problem.

+2
source

As others noted, List<SubChild> not a subclass of List<SuperChild> .

Depending on what you want to do, you can use generics:

 public class SuperParent<T extends SuperChild> { public List<T> getList() { return new ArrayList<T>(); } } public class SuperChild { } public class SubParent extends SuperParent<SubChild> { public List<SubChild> getList() { return new ArrayList<SubChild>(); } } public class SubChild extends SuperChild { } 
+2
source

Imagine something like this:

 SubParent subParent = new SubParent(); SuperParent superParent = (SuperParent) subParent; // upcast is okay List<SuperChild> list = superParent.getList(); list.add(new SuperChild()); 

The last statement would violate the SubParent contract.

The fix will be to change the SuperLarent getList contract to List<? extends SuperChild> getList() List<? extends SuperChild> getList() .

0
source

Source: https://habr.com/ru/post/1399799/


All Articles