JLS的哪一部分指定了您不能从List<转换?扩展List< Superclass>>列出< List< Subclass>&gt ;? [英] Which part of the JLS specifies that you can't cast from List<? extends List<Superclass>> to List<List<Subclass>>?

查看:58
本文介绍了JLS的哪一部分指定了您不能从List<转换?扩展List< Superclass>>列出< List< Subclass>&gt ;?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

(此问题的灵感来自此问题,我没有正确回答.)

(This question is inspired by this question, which I incorrectly answered.)

此代码无法编译:

List<? extends List<Number>> list = new ArrayList<>();
List<List<Double>> anotherList = (List<List<Double>>) list;

请注意,IntelliJ不报告任何错误.仅当我单击运行"时,它才能编译.

Note that IntelliJ doesn't report any errors. It only fails to compile when I click "Run".

我理解为什么它不能在概念上进行编译. list 是扩展了 List< Number> "的内容的列表,而该内容"则是永远不能是 List< Double> ,因为 List< Double> 不是 List< Number> 的子类型,并且因为没有类型可以实现因为它们具有相同的擦除.

I understand why this doesn't compile on a conceptual level. list is a list of "something that extends List<Number>", and that "something" can never be List<Double>, because List<Double> is not a subtype of List<Number>, and because no type can implement both since they have the same erasure.

但是,当我尝试按照语言规范中的措辞确定此强制转换是否有效时,我发现语言规范似乎说这是有效的强制转换!

However, when I tried to follow the wording in the language specification to determine whether this cast is valid, I found that the language spec seems to say that this is a valid cast!

这是我的理由:

强制转换满足从 S ( List< ;?扩展List< Number>> )到 T的缩窄引用转换的所有三个要求.( List< List< Double>> ).

The cast fulfils all three requirements for there to be a Narrowing Reference Conversion from S (List<? extends List<Number>>) to T (List<List<Double>>).

5.1.6.1 .允许缩小参考转换

5.1.6.1. Allowed Narrowing Reference Conversion

存在从参考类型S到参考类型的缩小参考转换如果满足以下所有条件,则引用类型T:

A narrowing reference conversion exists from reference type S to reference type T if all of the following are true:

  • S不是T的子类型

  • S is not a subtype of T

如果存在作为T的超类型的参数化类型X和作为S的超类型的参数化类型Y,使得X和Y的删除相同,则X和Y无法证明完全不同(第4.5节).

If there exists a parameterized type X that is a supertype of T, and a parameterized type Y that is a supertype of S, such that the erasures of X and Y are the same, then X and Y are not provably distinct (§4.5).

以下情况之一适用:

  • S和T是接口类型.
  • [...]

第一点和第三点都是正确的.为了表明第二点是正确的,我们将 Collection< List< Double>> 设为 List< List< List< Double> 的参数化超类型,并且集合< ;?将List< Number>> 扩展为 List< ;?的参数化超类型.扩展List< Number>> .它们都擦除为相同的 Collection 类型.现在我们需要显示 Collection< ;?不是

The first and third points are trivially true. To show that the second point is true, we take Collection<List<Double>> to be a parameterised super type of List<List<Double>>, and Collection<? extends List<Number>> to be a parameterised super type of List<? extends List<Number>>. They both erase to the same type Collection. Now we need to show that Collection<? extends List<Number>> and Collection<List<Double>> are not provably distinct (§4.5). The same argument also works for Iterable<...>.

我刚刚意识到 List< List< Double>> 的超类型还包括类似 List< ;?的东西.扩展List< Double>> ,而不仅仅是 List 的超级接口.但我认为这不会使该参数无效,因为要点是1.在 X Y 中至少有一个通配符2.通配符界限/ X Y 的类型参数是彼此的子类型.

I just realised that the supertypes of List<List<Double>> also include things like List<? extends List<Double>>, not just the superinterfaces of List. But I don't think that will invalidate this argument, as the point is that 1. out of X and Y there is at least one wildcard 2. the wildcard bounds/type arguments of X and Y are subtypes of each other.

如果两个参数化类型中的任何一个被证明是截然不同的以下是正确的:

Two parameterized types are provably distinct if either of the following is true:

  • 它们是不同的泛型类型声明的参数化.

  • They are parameterizations of distinct generic type declarations.

它们的任何类型自变量都可以证明是不同的.

Any of their type arguments are provably distinct.

很显然,由于它们都擦除为同一类型,因此第一个条件不能为真.我们只需要证明第二个条件为假即可.

Clearly, since they both erase to the same type, the first condition can't be true. We only need to show that the second condition is false.

§4.5中.1 ,该规范定义了类型参数是可证明是不同的":

In §4.5.1, the spec defines "type arguments are provably distinct":

如果满足以下条件之一,则两个类型实参可证明是不同的正确:

Two type arguments are provably distinct if one of the following is true:

  • [...]
  • 一个类型参数是类型变量或通配符,其上限(如有必要,来自捕获转换(第5.1.10节))为S;和其他类型参数T不是类型变量或通配符;而且都不| S |< ;: | T |也不| T |< ;: | S |(第4.8节,第4.10节).

(为简便起见,未显示其他(通常为假)条件)此处, S List< Number> ,而 T 列表< Double> .两者| S |< ;: | T |和| T |< ;: | S |保持为| S |和| T |是相同的类型.是的,子类型关系是自反的,因为超类型关系是自反的(在 direct 超类型关系上定义为自反和传递闭包).

(The other (trivially false) conditions are not shown for brevity) Here, S is List<Number> and T is List<Double>. Both |S| <: |T| and |T| <: |S| holds, as |S| and |T| are the same type. Yes, the subtype relation is reflexive, because the super type relation is reflexive (it's defined as the reflexive and transitive closure on the direct supertype relation).

因此, Collection<的类型实参?扩展List< Number>> Collection< List< Double>> 不能证明是不同的,所以 List< ;?扩展List< Number>> List< List< Double>> 不能证明是不同的,因此存在(或应该是 )转换来自 List< ;?将List< Number>> 扩展到 List< List< Double>>

Therefore the type arguments of Collection<? extends List<Number>> and Collection<List<Double>> are not provably distinct, and so List<? extends List<Number>> and List<List<Double>> are not provably distinct, and so there is (or should be) a conversion from List<? extends List<Number>> to List<List<Double>>!

我的推理错误在哪里?我错过了规格的其他部分吗?

Where is the error in my reasoning? Is there some other part of the spec that I missed?

推荐答案

好吧,我会在 Holger确认并回答后再说 :(至少)在此位置未指定JLS.有一些相关的JDK错误可以解决相同的想法,值得注意的是这一个,直接通过以下方式提示您的问题:

Well, I'll just say it after Holger's confirmation and answer: JLS is underspecified (at least) at this location. There are some related JDK bugs that work around the same idea, noticeable this one, that directly hits your question via:

....否则,将通配符和类型变量映射到它们的上限,然后测试它们的擦除是否是相关的类或接口(即,一种擦除的类型是另一种的子类型)

.... Otherwise, map wildcards and type variables to their upper bounds, and then test whether their erasures are related classes or interfaces (that is, one erased type is a subtype of the other)

仅可使用以下内容立即开始下一个句子:

Only to immediately start the next sentence with:

这很不完美...

This is unsound...

因此,该错误承认JLS需要围绕本章进行一些更正.

So, that bug admits that JLS needs some corrections around this chapter(s).

在您对JLS的引用中,我也一直在努力解决两点:

What I have been struggling with too from your quotes of the JLS are two points:

  • 一个类型参数是类型变量或通配符,其上限为(必要时来自捕获转换(第5.1.10节)) ...

我确实知道什么是捕获转换,但是我不知道执行该操作是否是可选的(通过如有必要").我一直以为它总是在每个位置执行.

I do know what capture conversion is, but I was not aware it might be optional to be performed (via that "if necessary"). I always thought that it is performed at each location, all the time.

捕获的转换类型的上限是什么?

What is an upper bound from a captured conversion type?

在您的情况下,例如,上限 列表< Number> 或 List<?> ?以我的理解(或缺乏确切的JLS解释),这两种方法都可以理解.

In your case, is that upper bound List<Number> or List<?>, for example? In my understanding (or lack of precise JLS explanation), this could be understood either way.

所有这些(加上您对JLS的极大了解)使我想知道这里JLS的正确性,尤其是因为 javac 没有遵循这些完全相同的规则.

All these (+ your great scrape of the JLS) makes me wonder about the correctness of the JLS here, especially since javac is not following these exact same rules.

这篇关于JLS的哪一部分指定了您不能从List&lt;转换?扩展List&lt; Superclass&gt;&gt;列出&lt; List&lt; Subclass&gt;&gt ;?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆