Enforcing return type for an class that implements an interface

后端 未结 7 1223
青春惊慌失措
青春惊慌失措 2021-01-11 11:51

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{
     ....
          


        
相关标签:
7条回答
  • 2021-01-11 12:24

    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.

    0 讨论(0)
  • 2021-01-11 12:29

    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() {
            // ...
        }
    }
    
    0 讨论(0)
  • 2021-01-11 12:30

    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.

    0 讨论(0)
  • 2021-01-11 12:32

    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
    0 讨论(0)
  • 2021-01-11 12:47

    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. :)

    0 讨论(0)
  • 2021-01-11 12:47

    Maybe sth like this

    public interface Bar {
         ....
         List<? extends Bar> getFoo(); 
    }
    
    public class T implements Bar {
         List<T> getFoo();
    }
    
    public class TestClass extends T {};
    
    0 讨论(0)
提交回复
热议问题