Полагайте, что у меня есть следующий интерфейс:
public interface A { public void b(); }
Однако я хочу каждый из классов, которые реализуют его, чтобы иметь другой тип возврата для метода b ().
Примеры:
public class C {
public C b() {}
}
public class D {
public D b() {}
}
Как я определил бы свой интерфейс так, чтобы это было возможно?
Если возвращаемый тип должен быть типом класса, который реализует интерфейс, тогда то, что вы хотите, называется F-ограниченным типом :
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() { ... }
}
Словами, A
объявляет параметр типа T
, который будет принимать от значения каждого конкретного типа, реализующего A
. Обычно это используется для объявления хорошо типизированных методов типа clone ()
или copy ()
. В качестве другого примера он используется java.lang.Enum
, чтобы объявить, что унаследованный метод compareTo (E)
каждого перечисления применяется только к другим перечислениям этого конкретного типа.
Если вы будете использовать этот шаблон достаточно часто, вы столкнетесь со сценариями, когда вам нужно, чтобы this
имел тип T
. На первый взгляд может показаться очевидным, что это 1 , но на самом деле вам нужно объявить абстрактный метод T getThis ()
, который разработчикам придется тривиально реализовать как верните это
.
[1] Как отмечали комментаторы, можно сделать что-то хитрое, например, X реализует A
, если X
и Y
взаимодействуют должным образом. Наличие метода T getThis ()
делает еще более ясным, что X
обходит намерения автора интерфейса A
.
Поскольку Java поддерживает ковариантные возвращаемые типы (начиная с Java 1.5), вы можете:
public interface A { public Object b(); }
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();
}
}
Поищите в generics для более подробной информации, но (очень) в основном происходит то, что A
оставляет тип E
на усмотрение реализующих классов (C
и D
).
Так что в основном A не знает (и не обязан знать), каким может быть E в любой конкретной реализации.