При возврате объекты разделяют на подклассы с дженериками

С абстрактным классом я хочу определить метод, который возвращает "это" для подклассов:

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 с сообщением "Не пирог!"

15
задан Sarabjot 19 July 2010 в 20:08
поделиться

4 ответа

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 . Это требование нельзя задать статической типизацией.

20
ответ дан 1 December 2019 в 00:49
поделиться

Подход, который я использовал раньше для достижения аналогичного поведения, состоит в том, чтобы подкласс передавал свой тип конструктору (обобщенного) родительского типа. В качестве заявления об отказе от ответственности я генерировал подклассы на лету, и наследование было чем-то вроде уловки, чтобы моя генерация кода была простой, как всегда, мой первый инстинкт - попытаться полностью удалить отношения extends.

0
ответ дан 1 December 2019 в 00:49
поделиться

Изящный подход с точки зрения клиента (обычно это тот, который вы хотите использовать) заключается в использовании ковариантных возвращаемых типов, которые, как указывает Майкл Баркер, были добавлены для поддержки дженериков.

Немного менее изящный, но более вкусный вариант приведения состоит в том, чтобы добавить метод getThis :

protected abstract T getThis();

public <T extends Foo> T eat(String eatCake) {
    ...
    return getThis();
}
17
ответ дан 1 December 2019 в 00:49
поделиться

Я не думаю, что вам нужны 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;
    }
}
5
ответ дан 1 December 2019 в 00:49
поделиться
Другие вопросы по тегам:

Похожие вопросы: