I J
I J

Reputation: 825

Enforcing return type for an class that implements an interface

How do I enforce that the method getFoo() in the implementing class, returns a list of the type of same implementing class.

public interface Bar{
     ....
     List<? extends Bar> getFoo(); 
}

Right now a class that implements Bar returns objects of any class that implements Bar. I want to make it stricter so that the class that implements Bar returns a List of objects of only its type in getFoo().

Upvotes: 17

Views: 18797

Answers (7)

Daniel Pryden
Daniel Pryden

Reputation: 60957

Unfortunately this cannot be enforced by Java's type system.

You can get pretty close, though, by using:

public interface Bar<T extends Bar<T>> {
    List<T> getFoo();
}

And then your implementing classes can implement it like so:

public class SomeSpecificBar implements Bar<SomeSpecificBar> {
    // Compiler will enforce the type here
    @Override
    public List<SomeSpecificBar> getFoo() {
        // ...
    }
}

But nothing stops another class from doing this:

public class EvilBar implements Bar<SomeSpecificBar> {
    // The compiler's perfectly OK with this
    @Override
    public List<SomeSpecificBar> getFoo() {
        // ...
    }
}

Upvotes: 25

emory
emory

Reputation: 10891

How about this:

interface Bar
{
    // everything but getFoo ( ) ;
}

interface FooGetter < T >
{
    List < ? extends T > getFoo ( ) ;
}

interface BarRef < T extends Bar & FooGetter < T > >
{
    T get ( ) ;
}

anything that implements BarRef must implement T and anything that implements T must have the appropriately enforced getFoo method.

Upvotes: 0

emory
emory

Reputation: 10891

I liked yshavit answer best but I could not understand the code. So I will try to write the code as I think it should be.

interface Bar
{
    // stuff
    // don't bother with the getFoo method
}

interface BarUtils
{
    < T extends Bar > List < ? extends T > getFoo ( T bar ) ;
}

Upvotes: 0

yshavit
yshavit

Reputation: 43391

The interface Bar<T extends Bar<T>> answers already here are right, but I just wanted to add that if this is really something you want to enforce, you may want to look at composing your objects rather than using inheritance. Without knowing too much about your classes, it might look something like this:

public interface FooGetter<T> {
    List<? extends T> getFoo();
}

public class FooComposer<T extends Bar> {
    ...
    final T bar;
    final FooGetter<T> barGetter;
}

Or it could look very different... but the main point is that if you want the two Ts to match, composition may be the answer.

Of course, even that can be circumvented using raw types... but then again, if someone does that, they're just using a raw List, and when they get ClassCastExceptions you can safely hit them. :)

Upvotes: 2

Robin
Robin

Reputation: 36601

This is not possible in Java, but you might wonder what the use-case is to force this in the interface.

  • If you program against the interface (which you typically do, why else define the interface) the type wouldn't be known
  • If you program against a specific class, this thread already provided options on how you can implement that specific class to return a List<itself>. And since you program against that specific class, the compiler has access to that specific return type and knows about it

Upvotes: 2

lord.didger
lord.didger

Reputation: 1407

Maybe sth like this

public interface Bar {
     ....
     List<? extends Bar> getFoo(); 
}

public class T implements Bar {
     List<T> getFoo();
}

public class TestClass extends T {};

Upvotes: 0

Jon Egeland
Jon Egeland

Reputation: 12613

You should infer the generic on Bar:

public interface Bar<T extends Foo> {
  ...
  List<T> getFoo();
}

You can just parameterize the method, but that will not ensure that the return type matches that of the class.

Upvotes: 1

Related Questions