当前位置: 首页 > 面试题库 >

通用返回类型上限-接口与类-出乎意料的有效代码

秦毅
2023-03-14
问题内容

这是来自第三方库API的真实示例,但已简化。

与Oracle JDK 8u72一起编译

考虑以下两种方法:

<X extends CharSequence> X getCharSequence() {
    return (X) "hello";
}

<X extends String> X getString() {
    return (X) "hello";
}

两者都报告“未经检查的演员表”警告-我明白原因。让我感到困惑的是为什么我可以打电话

Integer x = getCharSequence();

它可以编译吗?编译器应该知道Integer没有实现CharSequence。致电

Integer y = getString();

给出错误(按预期)

incompatible types: inference variable X has incompatible upper bounds

java.lang.Integer,java.lang.String

有人可以解释为什么将这种行为视为有效吗?有什么用?

客户端不知道此调用是不安全的-客户端代码在没有警告的情况下进行编译。为何编译器不会对此发出警告/发出错误?

此外,它与此示例有何不同:

<X extends CharSequence> void doCharSequence(List<X> l) {
}

List<CharSequence> chsL = new ArrayList<>();
doCharSequence(chsL); // compiles

List<Integer> intL = new ArrayList<>();
doCharSequence(intL); // error

尝试通过List<Integer>给出了一个错误,如预期的那样:

method doCharSequence in class generic.GenericTest cannot be applied to

given types;
required: java.util.List
found: java.util.List
reason: inference variable X has incompatible bounds
equality constraints: java.lang.Integer
upper bounds: java.lang.CharSequence

如果报告为错误,为什么Integer x = getCharSequence();不呢?


问题答案:

CharSequence是一个interface。因此,即使SomeClass不实现CharSequence,也完全有可能创建一个类

class SubClass extends SomeClass implements CharSequence

因此你可以写

SomeClass c = getCharSequence();

因为推断的类型X是相交类型SomeClass & CharSequence

在某些情况下,这是有点奇怪的,Integer因为它Integer是最终的,但final在这些规则中没有任何作用。例如你可以写

<T extends Integer & CharSequence>

另一方面,String由于不是interface,所以不可能扩展SomeClass以获得的子类型String,因为Java不支持类的多重继承。

在该List示例中,您需要记住,泛型既不是协变也不是协变。这意味着if
X是的子类型YList<X>既不是的子类型也不是的超类型List<Y>。由于Integer未实现CharSequence,因此无法List<Integer>在您的doCharSequence方法中使用。

您可以,但是可以将其编译

<T extends Integer & CharSequence> void foo(List<T> list) {
    doCharSequence(list);
}

如果你有一个方法 返回 一个List<T>像这样的:

static <T extends CharSequence> List<T> foo()

你可以做

List<? extends Integer> list = foo();

同样,这是因为推断的类型是,Integer & CharSequence并且这是的子类型Integer

当您指定多个边界(例如<T extends SomeClass & CharSequence>)时,交叉点类型隐式出现。

有关更多信息,这是JLS的一部分,其中解释了类型边界的工作方式。您可以包括多个接口,例如

<T extends String & CharSequence & List & Comparator>

但只有第一个边界可以是非接口。



 类似资料:
  • 这是一个来自第三方库API的真实示例,但经过了简化。 用Oracle JDK 8U72编译 考虑以下两种方法: 两者都报告了一个“未经检查的强制转换”警告--我知道原因了。让我困惑的是为什么我可以打电话 试图传递会出现错误,正如所料: 如果报告为错误,为什么不是?

  • 问题内容: 我正在玩Go,发现一个我无法解决的问题。假设我有如下代码: 我导入了软件包并开始使用它: 我真的很喜欢我的助手“运行”,但是我想使其更加慷慨:我不希望人们总是向我传递MySQL客户端。可以是具有“ RunQuery”和“ Result”方法的任何东西。所以我尝试使用接口: 可悲的是,这不再编译了。我收到此错误: Go不支持此功能吗,或者我做错了什么? 问题答案: 应该返回接口,否则你总

  • 我正在尝试返回一个对象,它应该是IClass的一个实现,具有一个通用类型,是IType的一个实现。 我要返回的实际类扩展了Class (abstract ),其泛型类型为ActualType: 抽象类对象实现了IClass接口,可以有任何扩展IType的类型 ActualType只是实现了IType接口 我在编译时得到一个“类型不匹配:无法从ActualClass转换为IClass”错误。我不明白

  • 我有几个具体的使用以下类型的接口 具体的课程如下 现在我怎么能写工厂类,它重新运行一个通用接口,比如IActive。 谢谢

  • 好吧,乖点。 这里有一个枚举,它实现了一个接口,该接口返回一个“原始类型”,它给我一个关于接口中的方法的警告。 如果我将接口的方法更改为: 它会在的方法签名上变为未经检查的警告。如果我改变的签名: 然后返回有一个不兼容的类型错误,因为

  • 问题内容: 我在接口上苦苦挣扎。考虑一下: 我希望函数返回a 或an ,具体取决于是否从或调用 当我尝试对此进行编译时,出现以下错误: 不能将s( StringGenerator类型)用作数组或切片文字中的Generator类型: StringGenerator不实现Generatorer(getValue方法的类型错误) 有getValue()字符串 要getValue() 我该如何实现? 问题