对于抽象类,我想定义一个为子类返回“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,并带有“Not a cake!”的消息。
答案 0 :(得分:20)
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
的类型。静态类型无法指定该要求。
答案 1 :(得分:17)
从客户的角度来看,这种有品味的方法(通常是你想要采用的方法)是使用协变返回类型,这是为了支持泛型,正如Michael Barker所指出的那样。
使用getThis
方法添加protected abstract T getThis();
public <T extends Foo> T eat(String eatCake) {
...
return getThis();
}
方法稍微不那么有品味但更有品味:
{{1}}
答案 2 :(得分:5)
我认为您不需要泛型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;
}
}
答案 3 :(得分:0)
我之前用来实现类似行为的方法是让子类将其类型传递给(generified)父类型的构造函数。通过免责声明,我正在动态生成子类,并且继承是让我的代码生成简单有点欺骗,因为我的第一直觉是尝试完全删除扩展关系。