18

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

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 并显示消息“不是蛋糕!”

4

4 回答 4

27
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. 该要求不能通过静态类型指定。

于 2010-07-19T20:24:53.713 回答
22

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

稍微没品位,但是比较有品位的演员就是加个getThis方法:

protected abstract T getThis();

public <T extends Foo> T eat(String eatCake) {
    ...
    return getThis();
}
于 2010-07-19T21:53:33.443 回答
8

我认为您不需要泛型 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;
    }
}
于 2010-07-19T20:12:07.640 回答
0

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

于 2010-07-20T00:24:36.460 回答