Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java generics - override a function that returns a set<T>

Tags:

java

generics

This works :

public interface A {
     A doSomething(); 
}

public interface B extends A{
     B doSomething(); 
}

This doesn't :

public interface A {
     Collection<A> doSomething(); 
}

public interface B extends A{
     Collection<B> doSomething(); 
}

Why? and what can I do to get the functionality I want in the second example?

like image 655
Yossale Avatar asked Jan 18 '23 22:01

Yossale


2 Answers

The reason is that Collection<B> is not a sub-type of Collection<A>.

Not every operation that's possible with a Collection<A> is also possible with a Collection<B>. Case in point: calling add(new A()) works with a Collection<A> but must fail with a Collection<B> (even if that's just checked at compile-time).

If you don't care about adding elements to the returned Collection (often you only care about iterating over them, effectively treating them as if they were read-only), then you can do this:

public interface A {
     Collection<? extends A> doSomething();
}

public interface B extends A{
     Collection<? extends B> doSomething();
}

You can even let B.doSomething() return a Collection<B> if you want, but then you won't be able to extend B in the same way again.

like image 71
Joachim Sauer Avatar answered Jan 21 '23 13:01

Joachim Sauer


Change it to:

public interface A {
    Collection<? extends A> doSomething();
}

public interface B extends A{
    Collection<B> doSomething(); 
}

and it'll work properly.

It's because "a collection of B" does not extend a collection of A", even though B extends A. A needs to define the return type as a "collection of items that extends A" than you can narrow it further as "a collection of B". Confusing, yes ... but that's just how it is.

like image 28
Reverend Gonzo Avatar answered Jan 21 '23 13:01

Reverend Gonzo