返回带有泛型的对象子类

问题描述 投票:0回答:4

对于抽象类,我想定义一个为子类返回“this”的方法:

public abstract class Foo {
    ...
    public <T extends Foo> T eat(String eatCake) {
        ...
        return this;
    }
}  

public class Eater extends Foo {}

我希望能够做这样的事情:

Eater phil = new Eater();
phil.eat("wacky cake").eat("chocolate cake").eat("banana bread");
java generics subclass parameterized return-type
4个回答
30
投票
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
的类型。该要求无法通过静态类型来指定。


24
投票

从客户端的角度来看(通常是您想要采用的方法),最有品味的方法是使用协变返回类型,该类型是为了支持泛型而添加的,正如 Michael Barker 指出的那样。

稍微没那么有品味,但是更有味道的演员就是加了一个

getThis
方法:

public abstract class Foo<T extends Foo<T>> {
    protected abstract T getThis();

    public T eat(String eatCake) {
        ...
        return getThis();
    }
}

public class CakeEater extends Foo<CakeEater> {
    @Override protected CakeEater getThis() {
        return this;
    }
}

9
投票

我认为你不需要泛型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;
    }
}

0
投票

我之前使用过的实现类似行为的方法是让子类将其类型传递给(泛化的)父类型的构造函数。作为免责声明,我是动态生成子类的,为了保持代码生成简单,继承有点作弊,因为我的第一直觉总是尝试完全删除扩展关系。

© www.soinside.com 2019 - 2024. All rights reserved.