从用<t extend =“” testclass =“”>概括的通用方法返回

时间:2018-12-08 14:56:34

标签: java generics compiler-errors return-type

为什么我不能用Java做到这一点?

public class TestClass {

    public <T extends TestClass> T test(){
        return this; // error here
    }
}

据我了解,this始终是扩展TestClass的某个类的实例,那么为什么编译器不允许上面的代码?即使我将扩展TestClass,但this的类型仍然适合extends TestClass。我收到以下错误:

  

错误:(4,16)java:不兼容的类型:无法转换TestClass   到T

3 个答案:

答案 0 :(得分:5)

假设您有SubTestClass extends TestClass,然后输入:

TestClass instance = new TestClass();
SubTestClass result = instance.test();

关于您的test()类的签名是合法的,尽管这是胡扯(1)。编译器将推论T是类SubTestClass。然后很明显TestClass实例不是instanceof SubTestClass。因此,在合法使用test()方法的情况下,返回this可能会导致类型不匹配,而这正是编译器告诉您的。

使用您的test()签名,就无法返回null以外的任何内容,因为null是您可以分配给未知类型变量的唯一值。

让我解释一下最后的要求(在注释中要求):test()方法的实现必须返回一些与T类型和具体类型相匹配的值(由调用得出)这种情况无法推断出SubTestClass的情况-参数或实例字段中没有任何内容可以读取这种情况下返回SubTestClass的要求。在另一种通话情况下,可能需要返回AnotherSubTestClass,并且无法从第二种情况中分辨出第一种。

如果您返回this(使用(T)进行强制转换以使其通过编译器),则在第一种,第二种或两种情况下都会失败。因此,如果没有很高的失败风险,您将无法做到这一点。

可以成功分配给SubTestClassAnotherSubTestClass变量的唯一值是null值。因此,这是可以从具有这种签名的方法中安全返回的唯一值。

(1)有一个通用方法,该通用方法无法从参数中推导通用类型,而只能从预期结果类型推导,几乎无法工作-该方法应如何知道调用者的期望?

答案 1 :(得分:-1)

您误会了一些东西

  

据我了解,this永远是某个扩展TestClass的类的实例

那是不对的,this可以是TestClass本身的一个实例。这就是编译器损坏的原因。为了解决这个问题,您应该将this强制转换为T

return (T) this;

编辑01:

顺便说一句,如果您想做这样的事情,我还建议您添加这两个选项之一,以防止RuntimeError:

  • TestClass设置为抽象类
  • 请确保this不是TestClass的实例,您可以使用类似以下的方法:this.getClass().equals(TestClass.class)

希望这会有所帮助。

答案 2 :(得分:-1)

“此”表示类“ TestClass”,因为TestClass是T的superClass,superClass无法转换为子类,但是您可以尝试强制类型转换,或将返回类型设置为“ TestClass”。

public <T extends TestClass> T test() {
    return (T)this;
}

编辑01: 强制转换错误,可能会导致运行时错误。