无法理解java通配符

时间:2014-10-08 12:27:03

标签: java wildcard covariance

我尝试从我的Main获取foo():

<T extends Main> T foo()
{
  return this; // "this" it is a instance of Main
}

并使用它

Main m = new Main();
Main m2 = m.foo();

我遇到了错误:&#34; 不兼容的类型。必填T,找到主&#34;在方法foo()中。
我知道我可以用这个:

<T extends Main> T foo2(T a) {
  return a;
}

并使用它:

Main m = new Main();
Main m3 = m.foo2(m);

它工作正常。但我无法理解,为什么我不能使用第一种方法?因为this绝对是Main的实例扩展。

3 个答案:

答案 0 :(得分:8)

如果您在类型<T extends Main> T foo();中定义Main,则无法返回this,因为T可能是Main的子类型,Main当然不是。因此,如果你有MainSubType m = new Main().foo();编译器希望TMainSubType,但面对它只有Main类型,所以你必须用艰难的方式解析它,我不能在这里推荐,但这就是你如何去<T extends Main> T foo(){return (T) this}。如果你这样做,你应该能够编译其余部分。

如果它不适用于foo()中的(T)-cast,则需要提供更多上下文/代码。

答案 1 :(得分:2)

作为user2504380 already pointed out:如果可能的话,你可以默默地&#34; upcast&#34;任何MainMain的任何子类。

但是,你可能根本不需要这个类型参数(至少,我无法想象它可能有意义的情况)。如果你的班级是这样的:

class Main {
    Main getIt() {
        return this;
    }
}

然后你可以创建Main的子类,并且,由于Java中的covariance,重写方法以返回相应的Main

子类型
class SubMain {

    // Overriding with a more specific return type:
    @Override
    SubMain getIt() {
        return this;
    }
}

这意味着方法的返回类型由您调用方法的引用类型决定:

Main main = new Main();
SubMain subMain = new SubMain();

Main m0 = main.getIt();
Main m1 = subMain.getIt();

// This does not work
//SubMain s0 = main.getIt();

// But this works: The instance IS a SubMain, and returns a SubMain:
SubMain s1 = subMain.getIt();

在涉及自引用泛型类型的更复杂的场景中,您可以使用getThis trick

答案 2 :(得分:0)

正如其他人已经指出的那样,

 <T extends Main> 

编译器无法确定T的类型。它可以是Main或Main的任何子类。由于这种不确定性,编译器不允许返回它。如果你使用T之类的

来转换retrun类型
(T) this 

或者如果存在类型为T的方法参数,则没有不确定性。