Interfaces, generics, and covariant return types

610 views Asked by At

Suppose I have an interface as follows:

public interface Foo<T> {
    T doSomething();
}

Now, are both the following allowed?

public class Bar implements Foo<Number> { ... }

public class Bar2 extends Bar implements Foo<Integer> { ... }

On one hand, I seem to not think so, since Bar2 "implements Foo twice", even though Integer is a subclass of Number. On the other hand, wouldn't this be a case of covariant return type on doSomething()? Or is the compiler not smart enough to detect as such?

2

There are 2 answers

0
Mustafa sabir On

This is not an interface, it seems to be a class(or abstract class which is also missing the keyword abstract), it should be like:-

public interface Foo<T> {
        T doSomething();
}

Besides

public class Bar implements Foo<Number> { ... }

public class Bar2 extends Bar implements Foo<Integer> { ... }

Will give you compile time error , The interface Foo cannot be implemented more than once with different arguments: Foo<Number> and Foo<Integer>

But if you instead do :-

public class Bar implements Foo<Integer> { ... }

public class Bar2 extends Bar implements Foo<Integer> { ... }

This will not give an compile time error, and if you implement doSomething() in Bar2 it will take that into consideration when you do :-

Bar2 bar2=new Bar2();
bar2.doSomething();

or else it will run the doSomething() from Bar

and obviously if you do:-

Bar bar=new Bar();
bar.doSomething();

it will take into consideration doSomething() of Bar , since it does have only one implemented doSomething() into account this time , i.e of Bar(which you have to implement since Bar is implementing the interface Foo :) )

0
Radiodef On

If Foo is meant to be an interface:

A class may not at the same time be a subtype of two interface types which are different parameterizations of the same generic interface [...], or a compile-time error occurs.

So no. (JLS 8.1.5)

And it would not really make sense anyway because you would be downcasting whatever Bar happens to return from doSomething. Maybe it's a Double.

On the other hand, you may still do:

class Bar2 extends Bar {
    @Override
    public Integer doSomething() {...}
}

Or is the compiler not smart enough to detect as such?

What we and the compiler think doesn't matter here. The compiler is bound to the language specification which dictates an error.