gpt4 book ai didi

java - 泛型方法实现中的不同返回值类型

转载 作者:IT老高 更新时间:2023-10-28 20:56:15 26 4
gpt4 key购买 nike

今天,我偶然发现了一些我什至没想到会编译的有效 Java 代码。减少到最低限度,它看起来像这样:

import java.util.List;

interface A {
<T> List<String> foo();
}

interface B {
<T> List<Integer> foo();
}

class C implements A, B {
@Override
public List<?> foo()
{
return null;
}
}

乍一看,类型参数<T>foo A 中的方法和 B看起来没必要因为 T不在其他任何地方使用。无论如何,我发现这在允许冲突的返回值类型在同一实现中共存方面起着至关重要的作用:如果 <T> 中的一个或两个s 被忽略,代码无法编译。这里是非工作版本:

import java.util.List;

interface A {
List<String> foo();
}

interface B {
List<Integer> foo();
}

class C implements A, B {
@Override
public List<?> foo()
{
return null;
}
}

我不需要修复上面的代码片段,因为这些只是我为解释我的观点而编造的示例。我只是想知道为什么编译器对它们的行为不同。有人能解释一下究竟是什么规则在这里产生了影响吗?

最佳答案

当第一个示例编译时,它会给出一个未经检查的转换警告:

// Type safety: The return type List<?> for foo() from the type C needs
// unchecked conversion to conform to List<String>
public List<?> foo()
{
return null;
}

这里发生的是通过声明类型参数,A.foo()B.foo()generic methods .然后,覆盖 C.foo()省略该类型参数。这类似于使用 raw type ,本质上是“选择退出”对该方法签名的泛型类型检查。这会导致编译器使用继承方法的 erasures改为:List<String> foo()List<Integer> foo()都变成 List foo() ,因此可以通过 C.foo() 实现.

您可以通过将类型参数保留在 C.foo() 中来看到这一点。声明,将会出现预期的编译器错误:

// The return type is incompatible with A.foo()
public <T> List<?> foo()
{
return null;
}

同样,如果任一接口(interface)方法未声明类型参数,则从覆盖中省略类型参数将无法“退出”对该方法的泛型类型检查,并且返回类型 List<?>仍然不兼容。

JLS §8.4.2 中涵盖了此行为:

The notion of subsignature is designed to express a relationship between two methods whose signatures are not identical, but in which one may override the other. Specifically, it allows a method whose signature does not use generic types to override any generified version of that method. This is important so that library designers may freely generify methods independently of clients that define subclasses or subinterfaces of the library.

Angelika Langer 的泛型常见问题解答在她的部分 Can a non-generic method override a generic one? 中对此行为进行了扩展。 :

Now, let us explore an example where non-generic subtype methods override generic supertype methods. Non-generic subtype methods are considered overriding versions of the generic supertype methods if the signatures' erasures are identical.

Example (of non-generic subtype methods overriding generic supertype methods):

class Super { 
public <T> void set( T arg) { ... }
public <T> T get() { ... }
}
class Sub extends Super {
public void set( Object arg) { ... } // overrides
public Object get() { ... } // overrides with unchecked warning
}

warning: get() in Sub overrides <T>get() in Super;  
return type requires unchecked conversion
found : Object
required: T
public Object get() {

Here the subtype methods have signatures, namely set(Object) and get() , that are identical to the erasures of the supertype methods. These type-erased signatures are considered override-equivalent.

There is one blemish in the case of the get method: we receive an unchecked warning because the return types are not really compatible. The return type of the subtype method get is Object , the return type of the supertype method get is an unbounded type parameter. The subtype method's return type is neither identical to the supertype method's return type nor is it a subtype thereof; in both situations the compiler would happily accept the return types as compatible. Instead, the subtype method's return type Object is convertible to the supertype method's return type by means of an unchecked conversion. An unchecked warning indicates that a type check is necessary that neither the compiler nor the virtual machine can perform. In other words, the unchecked operation is not type-safe. In case of the convertible return types someone would have to make sure that the subtype method's return value is type-compatible to the supertype method's return type, but nobody except the programmer can ensure this.

关于java - 泛型方法实现中的不同返回值类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20410837/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com