Когда у меня есть интерфейс
public interface Foo<T> {
T someMethod();
}
есть ли любой способ гарантировать, что, когда некоторый класс реализует этот интерфейс затем, универсальный тип является тем же implementig классом.
Например:
public class Bar implements Foo<Bar> {
Bar someMethod() {
return new Bar();
}
}
Да, это можно сделать (вроде как; см. ниже). (В мире С++ это называется "Curiously Recurring Template Pattern", но это относится и к Java):
public interface Recur<T extends Recur<T>> {
// ...
}
(Обратите внимание на второе упоминание T
. Это существенная часть CRTP.)
Также, так определено java.util.Enum
, так что тип перечисления под названием Foo
должен происходить из Enum
, так что это также не редкий шаблон на Java.
Хотелось бы сказать, что вышесказанное - это конец истории, но в их ревизии справедливо отмечается, что это не совсем надежно, и на самом деле не все так отличается от их ответа в характере.
Есть одно различие (я могу придумать) между Recur
решением, которое у меня есть, и Recur>
решением, которое имеет касательные:
public interface Recur<T extends Recur<T>> {
T foo();
}
class A implements Recur<B> {
@Override
public B foo() {
return new B();
}
}
class B implements Recur<A> {
@Override
public A foo() {
return new A();
}
}
С
, вышеуказанное не скомпилировалось бы; с >
, скомпилировалось бы. Но это просто расщепление волос; это не меняет центральную точку касательной, которая заключается в том, что при уже действительной реализации Recur
, Вы можете заставить последующие реализации использовать уже действительный тип, а не саму себя. Я по-прежнему говорю, что это чего-то стоит, но это не стоит больше, чем ответ касательной.
В заключение, если можно, тоже голосуйте за ответ касательно касательной. (Тангенс, вы должны прикоснуться к своему посту, чтобы я тоже мог проголосовать.) У них очень хорошая точка зрения, и мне жаль, что я пропустил ее в первый раз. Спасибо, Тангенс!
Я не могу подать Простое «Нет» На этом сайте (тело слишком короткое), так вот идет.
нет.
Это не может быть сделано из-за Type Strasure .
Отредактируйте:
Я спустился голосовал, здесь больше объясняется:
public interface Foo<T>;
T
. Выше доступно во время выполнения, поэтому его нельзя проверить. Тем не менее, можно пользовательскую аннотацию, которое могло бы принять это.
Нет, вы не можете ссылаться на реализующий класс. Лучшее, что вы могли бы сделать, это:
public interface Foo<T extends Foo<?> > {
T someMethod();
}
Сделав это, вы можете быть уверены, что someMethod ()
вернет объект, реализующий Foo
.
РЕДАКТИРОВАТЬ:
Даже с таким определением интерфейса:
public interface Foo<T extends Foo<T > > {
T someMethod();
}
Вы можете определить класс Bar2
public class Bar2 implements Foo<Bar2 > {
@Override
public Bar2 someMethod() {
return new Bar2();
}
}
А затем вы можете определить класс Bar
, который реализует Foo
, но не возвращает Bar
, но Bar2
:
public class Bar implements Foo<Bar2 > {
@Override
public Bar2 someMethod() {
return new Bar2();
}
}
Первоначальный вопрос заключался в том, можете ли вы подготовиться к использованию такого интерфейса, как Bar
сделал.
И ответ: Нет.
РЕДАКТИРОВАТЬ:
Анжелика Лангер дает хорошее объяснение Как мне расшифровать «Enum