С абстрактным классом я хочу определить метод, который возвращает "это" для подклассов:
public abstract class Foo {
...
public <T extends Foo> T eat(String eatCake) {
...
return this;
}
}
public class CakeEater extends Foo {}
Я хочу смочь сделать вещи как:
CakeEater phil = new CakeEater();
phil.eat("wacky cake").eat("chocolate cake").eat("banana bread");
Возможно банановый хлеб бросил бы IllegalArgumentException с сообщением "Не пирог!"
public abstract class Foo<T extends Foo<T>> // see ColinD's comment
{
public T eat(String eatCake)
{
return (T)this;
}
}
public class CakeEater extends Foo<CakeEater>
{
public void f(){}
}
Править
Нет проблем, требовать, чтобы подкласс вел себя определенным образом, за пределами того, что может проверить статическая типизация. Мы делаем это постоянно - страницы и страницы на простом английском языке, чтобы указать, как вы пишете подкласс.
Другое предложенное решение с ковариантным возвращаемым типом должно делать то же самое - предлагать разработчикам подкласса на простом английском языке вернуть тип this
. Это требование нельзя задать статической типизацией.
Подход, который я использовал раньше для достижения аналогичного поведения, состоит в том, чтобы подкласс передавал свой тип конструктору (обобщенного) родительского типа. В качестве заявления об отказе от ответственности я генерировал подклассы на лету, и наследование было чем-то вроде уловки, чтобы моя генерация кода была простой, как всегда, мой первый инстинкт - попытаться полностью удалить отношения extends.
Изящный подход с точки зрения клиента (обычно это тот, который вы хотите использовать) заключается в использовании ковариантных возвращаемых типов, которые, как указывает Майкл Баркер, были добавлены для поддержки дженериков.
Немного менее изящный, но более вкусный вариант приведения состоит в том, чтобы добавить метод getThis
:
protected abstract T getThis();
public <T extends Foo> T eat(String eatCake) {
...
return getThis();
}
Я не думаю, что вам нужны generics Java 5 (и более поздние версии) имеет ковариантные возвращаемые типы, например:
public abstract class Foo {
...
public Foo eat(String eatCake) {
...
return this;
}
}
public class CakeEater extends Foo {
public CakeEater eat(String eatCake) {
return this;
}
}