如何返回参数化返回类型的子类,其参数类型是返回类型的参数类型的子类?

时间:2014-04-09 18:38:33

标签: java generics java-6 parameterized-types

标题听起来有点复杂,但事实上问题很简单。 我有以下方法:

AbstractClassA<AbstractClassB> myMethod() {...}

我想这样调用它:

ClassAImpl<ClassBImpl> result = myMethod();

问题在于无论我尝试什么,我最终都会遇到unchecked cast警告或编译错误。

这样做的正确方法是什么?

3 个答案:

答案 0 :(得分:1)

一切都取决于。最简单的答案是,您只需要将myMethod的结果转换为与结果相同的类型。假设我们从问题中解决了所有泛型问题,例如:

public class Demo {

    private abstract class AbstractClassA {}
    private class ClassAImpl extends AbstractClassA {}
    private abstract class AbstractClassB {}
    private class ClassBImpl extends AbstractClassB {}

    Demo() {
        ClassAImpl result = myMethod();
    }
    public AbstractClassA myMethod() {
        return new ClassAImpl();
    }
    public static void main(String[] args) {
        new Demo();
    }
}

myMethod的调用仍然是编译器错误,因为类型不匹配。考虑这一点的一个好方法是想象你对myMethod正文中的代码一无所知。你怎么知道它返回ClassAImpl而不是AbstractClassA的其他子类型?因此,为了使其工作,您需要像这样调用myMethod

ClassAImpl result = (ClassAImpl)myMethod()

至于泛型位,您可能希望您的方法签名类似于:

public AbstractClassA<? extends AbstractClassB> myMethod()

但也许想要这样的事情:

public AbstractClassA<ClassBImpl> myMethod()

甚至:

public ClassAImpl<ClassBImpl> myMethod()

除了最后一个之外的所有内容都需要一些明确的演员。

答案 1 :(得分:1)

为什么你到底会这样做呢?你的设计是错误的,或者你遗漏了一些重要的信息。如果myMethod与尝试的调用位于同一个类中,那么您的调用者可以了解有关如何实现该方法的信息,那么您应该创建一个返回更具体类型的私有myMethodAux。但是,您可能仍会遇到方差问题,因为ClassAImpl<ClassBImpl>不是AbstractClassA<AbstractClassB>的子类。它是AbstractClassA<? extends AbstractClassB>的子类。

上面的评论似乎表明您不了解Java中子类型关系的这种差异限制。

答案 2 :(得分:0)

  

如果没有显式类型转换,则无法将超类型指定为子类型。

在向下投射之前使用instanceof运算符。


尝试Class#isInstance()

abstract class AbstractClassA<T extends AbstractClassB> {}

abstract class AbstractClassB {}

class ClassAImpl<T extends AbstractClassB> extends AbstractClassA<T> {}

class ClassBImpl extends AbstractClassB {}

...

public static AbstractClassA<? extends AbstractClassB> myMethod() {
    return new ClassAImpl<ClassBImpl>();
}

...

AbstractClassA<? extends AbstractClassB> returnValue=myMethod();
if(returnValue.getClass().isInstance(new ClassAImpl<ClassBImpl>())){
    ClassAImpl<ClassBImpl> result=(ClassAImpl<ClassBImpl>)returnValue;
    ...
}