Java泛型 – 为什么返回超类实例会导致编译错误

huangapple go评论76阅读模式
英文:

Java Generics - Why returning super class instance gives compile error

问题

class SomeClass <T extends BaseClass> {
    T method(T x) {
        return x;                   // OK
    }
    
    T method() {
        return new BaseClass();    // compile error
    }
}

错误提示为需要 T,但提供了 BaseClass

class SomeClass {
    <T extends BaseClass> T method(T x) {
        return x;                          // OK
    }
    
    <T extends BaseClass> T method() {
        return new BaseClass();           // compile error
    }
}

同样地,这段代码也会报错。

可以这样解决:

class SomeClass <T extends BaseClass> {
    T method(T x) {
        return x;                       // OK
    }
    
    @SuppressWarnings("unchecked")
    T method() {
        return (T) new BaseClass();    // OK
    }
}

以下是为什么不允许这样的解释:

这个问题涉及到 Java 泛型的类型擦除(Type Erasure)。在 Java 中,泛型是在编译时进行类型检查的,而在运行时会将泛型类型擦除,以便与旧版本的 Java 代码兼容。在编译后的字节码中,泛型类型信息被移除,所以编译器无法确定在返回语句中的具体类型。

在第一个代码示例中,T 是一个泛型类型参数,它被限定为必须是 BaseClass 的子类。在 method() 中,您尝试返回一个新的 BaseClass 实例,但是在类型擦除后,编译器无法确定返回值的类型是否与泛型参数匹配。因此,编译器会报错,指出需要类型 T,但实际提供的是 BaseClass 类型。

同样地,在第二个代码示例中,您在方法签名中引入了泛型类型参数 <T extends BaseClass>,但是在返回语句中尝试返回一个新的 BaseClass 实例。由于类型擦除,编译器无法保证返回的类型与泛型参数相匹配,因此会报错。

您提供的解决方法利用了强制类型转换来绕过编译器的检查。然而,这也会带来风险,因为编译器无法验证强制转换是否安全。通常情况下,推荐避免这种情况,以避免在运行时出现类型转换异常。

希望这些解释对您有所帮助!

英文:

Hi the following code gives compile error but I do not understand why.

class SomeClass &lt;T extends BaseClass&gt; {
    T method(T x) {
        return x;                   // OK
    }
    
    T method() {
        return new BaseClass();    // compile error
    }
}

The error says requires T but provided BaseClass.<br>
And similarly this one:

class SomeClass {
    &lt;T extends BaseClass&gt; T method(T x) {
        return x;                          // OK
    }
    
    &lt;T extends BaseClass&gt; T method() {
        return new BaseClass();           // compile error
    }
}

I know that it can be resolved like this:

class SomeClass &lt;T extends BaseClass&gt; {
    T method(T x) {
        return x;                       // OK
    }
    
    @SuppressWarnings( &quot;unchecked&quot; )
    T method() {
        return (T) new BaseClass();    // OK
    }
}

But may I have some explanation on why this is not allow?

答案1

得分: 3

这就是继承的工作原理。假设你有一个超类 A,它有子类 B 和 C。现在想象一下,你的方法接受一个类型为 A 的参数,并返回一个类型为 B 的对象。你的方法会接受类型为 C 的对象作为参数,但不能返回它们,因为它们不是类型为 B,尽管 B 和 C 都是 A 的子类。

英文:

That's just how inheritance works. Say you have a superclass A, and it has subclasses B and C. Now imagine your method accepts a parameter of type A and returns an object of type B. Your method would accept objects of type C as a parameter, but you couldn't return them because they are not of type B, even though both B and C are subclasses of A.

huangapple
  • 本文由 发表于 2020年8月21日 14:38:50
  • 转载请务必保留本文链接:https://go.coder-hub.com/63517702.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定