Java interfaces and return types

2019-01-08 21:34发布

问题:

Consider I have the following interface:

public interface A { public void b(); }

However I want each of the classes that implement it to have a different return type for the method b().

Examples:

public class C { 
  public C b() {} 
}

public class D { 
  public D b() {} 
}

How would I define my interface so that this was possible?

回答1:

If the return type must be the type of the class that implements the interface, then what you want is called an F-bounded type:

public interface A<T extends A<T>>{ public T b(); }

public class C implements A<C>{
  public C b() { ... }
}

public class D implements A<D>{
  public D b() { ... }
}

In words, A is declaring a type parameter T that will take on the value of each concrete type that implements A. This is typically used to declare things like clone() or copy() methods that are well-typed. As another example, it's used by java.lang.Enum to declare that each enum's inherited compareTo(E) method applies only to other enums of that particular type.

If you use this pattern often enough, you'll run into scenarios where you need this to be of type T. At first glance it might seem obvious that it is1, but you'll actually need to declare an abstract T getThis() method which implementers will have to trivially implement as return this.

[1] As commenters have pointed out, it is possible to do something sneaky like X implements A<Y> if X and Y cooperate properly. The presence of a T getThis() method makes it even clearer that X is circumventing the intentions of the author of the A interface.



回答2:

Generics.

public interface A<E>{
    public E b();
}

public class C implements A<C>{
    public C b(){
        return new C();
    }
}

public class D implements A<D>{
    public D b(){
        return new D();
    }
}

Search up generics for more details, but (very) basically, what's happening is that A leaves E's type up to the implementing clases (C and D).

So basically A doesn't know (and doesn't have to know) what E might be in any given implementation.



回答3:

Since Java supports covariant return types (since Java 1.5), you can do:

public interface A { public Object b(); }