Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

overriding list result type in java

I would like some variant of this code to compile in java.

class X
{
    List<X> getvalue(){...};
}

class Y extends X
{
    List<Y> getvalue(){...};
}

Javac (1.6) returns an error because List<Y> and List<X> are not compatible.

The point is that I would like the compiler to recognize that List<Y> is a compatible return type to List<X> if Y is a subtype of X. The reason I want this is to simplify the use of a user-defined factory class.

Note: This question is somewhat like this question but for java.

like image 931
Dennis Heimbigner Avatar asked Sep 10 '10 19:09

Dennis Heimbigner


People also ask

Is return type should be same in overriding in Java?

When we override a parent class method, the name, argument types, and return type of the overriding method in child class has to be exactly the same as that of the parent class method. The overriding method was said to be invariant with respect to return type.

Can you override return type Java?

From Java 5 onwards, we can override a method by changing its return type only by abiding the condition that return type is a subclass of that of overridden method return type.

Can a return type be different in overridden method?

Yes. It is possible for overridden methods to have different return type . But the limitations are that the overridden method must have a return type that is more specific type of the return type of the actual method.

What rules apply to return types for overridden methods?

The overriding method has the same name, number and type of parameters, and return type as the method that it overrides. An overriding method can also return a subtype of the type returned by the overridden method. This subtype is called a covariant return type.


2 Answers

In Java, the return type of the overriding method has to be covariant with that of the method being overridden.

The class java.util.List is not covariant (In fact, no Java class is. This happens because of the lack of declaration-site variance annotations). In other words, B <: A doesn't imply List<B> <: List<A> (read <: as is-subtype-of). Hence your code doesn't typecheck.


In Java, you have definition-site variance. The following therefore typechecks:

import java.util.List;

class X {
  List<? extends X> getvalue() { return null; }
}

class Y extends X {
  List<Y> getvalue() { return null; }
}
like image 194
missingfaktor Avatar answered Sep 20 '22 18:09

missingfaktor


No, it's not a compatible type. You can't convert from List<Y> to List<X> just because Y is a subclass of X. Consider:

List<Banana> bananas = new ArrayList<Banana>();
List<Fruit> fruit = bananas;
fruit.add(new Apple());
Banana banana = fruit.get(0); // But it's an apple!

You can use bounded wildcards in Java to express limited variance, giving something which is valid:

List<? extends Fruit> fruit = bananas;

because that will prevent you (at compile-time) from trying to add any extra fruit - the compiler knows it might be invalid.

I would recommend Angelika Langer's Java Generics FAQ for further reading about this sort of thing.

like image 30
Jon Skeet Avatar answered Sep 21 '22 18:09

Jon Skeet