Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/315.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 返回具有泛型的objects子类_Java_Generics_Subclass_Parameterized_Return Type - Fatal编程技术网

Java 返回具有泛型的objects子类

Java 返回具有泛型的objects子类,java,generics,subclass,parameterized,return-type,Java,Generics,Subclass,Parameterized,Return Type,对于抽象类,我想定义一个方法,为子类返回“this”: public abstract class Foo { ... public <T extends Foo> T eat(String eatCake) { ... return this; } } public class CakeEater extends Foo {} 可以说香蕉面包会抛出一个带有消息“不是蛋糕!”的IllegalArgumentExcepti

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

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

public class CakeEater extends Foo {}

可以说香蕉面包会抛出一个带有消息“不是蛋糕!”的IllegalArgumentException

我认为您不需要泛型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;
    }
}
公共抽象类Foo//参见ColinD的注释
{
公众不吃(串吃蛋糕)
{
返回(T)这个;
}
}
公共类CakeEater扩展了Foo
{
public void f(){}
}
编辑

要求子类以静态类型无法检查的特定方式运行是没有问题的。我们一直在这样做——一页又一页的纯英语来指定如何编写子类


另一个建议的解决方案,使用协变返回类型,必须做同样的事情——用简单的英语要求子类实现者返回
this
的类型。这一要求不能通过静态类型来指定。

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

演员阵容的品味稍差,但更高雅的是添加一个
getThis
方法:

protected abstract T getThis();

public <T extends Foo> T eat(String eatCake) {
    ...
    return getThis();
}
protected abstract T getThis();
公众不吃(串吃蛋糕){
...
返回getThis();
}

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

如果它在超类中完全定义,那么它会创建冗余代码来在子类中定义它;它可以调用超类,但这似乎没有必要。如果将此类型转换为T类型并抑制警告,则此选项有效。如果将此类型转换为T类型并抑制警告,则此选项有效。它应该返回子类类型的原因是:methodTakesCakeEater((新的CakeEater).eat(“蛋糕”).eat(“馅饼”);methodTakesCakeEater需要一个CakeEater参数。如果解决方案包含
@SuppressWarnings
,则不应将其视为解决方案。只要我的两分钱。我认为这不是解决草图问题的好方法,因为它需要覆盖子类中的所有方法,几乎不值得付出任何努力。想法是拥有一个流畅的API子类可以利用,而不是重写。我也不认为这是“前卫的”需要忽略或抑制警告的内容应该是
Foo
。这是可行的,尽管您可以轻松创建一个类,当您调用
eat
,例如
class Bar extensed Foo
时,该类将以
ClassCastException
爆炸。这是我最终使用的解决方案,但您会注意到返回的是一个未检查的cast警告。虽然从逻辑上讲,我们可以强制转换为T,因为这是T的一个子类。是的。在一个更好的世界中,Java可以有一个
this
类型,这在很多情况下都非常有用。
class FakeEater扩展了Foo{}
现在注意这个警告。Tom,我没有注意到任何警告。也许这就是你的回答,没有编译时警告。调用FakeEater的eat时,会出现编译时异常,返回的类型不是FakeEater类型,如果它被分配给FakeEater字段。
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(){}
}
protected abstract T getThis();

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