Dennis Heimbigner
Dennis Heimbigner

Reputation: 173

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.

Upvotes: 5

Views: 1609

Answers (2)

Jon Skeet
Jon Skeet

Reputation: 1502546

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.

Upvotes: 6

missingfaktor
missingfaktor

Reputation: 92076

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; }
}

Upvotes: 8

Related Questions