【问题标题】:Parameterization Well Formedness and Capture Conversion in JavaJava中的参数化格式良好和捕获转换
【发布时间】:2015-06-11 11:39:23
【问题描述】:

给定以下两个类定义:

class C1<T extends C1<T>> {}

class C2<U> extends C1<C2<U>> {}

还有以下类型声明:

C1<C2<?>> a;

直觉上感觉声明的类型a 应该是有效的,但这不是JDK-8u45 的行为方式。相反,我们得到如下输出:

Test.java:3: error: type argument C2<?> is not within bounds of type-variable T
        C1<C2<?>> a;
             ^
  where T is a type-variable:
    T extends C1<T> declared in class C1
1 error

(编辑:我在这里是个丁格斯,这部分已经回答了:C2&lt;?&gt; 扩展C1&lt;C2&lt;?&gt;&gt;。关于@声明的问题不过,下面的 987654334@ 仍然是一个悬而未决的问题。)

但是C2&lt;?&gt; 确实扩展了C1&lt;C2&lt;?&gt;&gt;,这似乎很容易满足界限。据我所知,对JLS 的检查没有提供进一步的照明。它真的应该像满足子类型关系的约束一样简单,因为C2&lt;?&gt; 不是通配符类型,因此捕获转换只是参数上的身份转换。

在某些情况下它变得不太清楚,例如,采用以下类定义:

class C3<T extends C3<?>> {}

class C4<Y, Z> extends C3<C4<Z, Y>> {}

class C5<X extends C3<X>> {
    void accept(X x);
}

这一切都很好,但是如果我们尝试以下声明:

C5<C6<?, ?>> b;

事情变得陌生。 C6&lt;?, ?&gt;C3&lt;C6&lt;?, ?&gt;&gt; 的子类型,因此根据我对上述关于声明 C1&lt;C2&lt;?&gt;&gt; 的规范的解释,声明应该是有效的。问题是显然不是C6&lt;?, ?&gt; 的每个可能的子类型实际上都满足该界限,所以现在例如C5.accept() 将其参数类型解析为C6&lt;?, ?&gt;,因此可以接受违反X 界限的参数,即任何地方YZ 的参数化不完全相同。

我哪里错了?我对亚型关系的理解不够吗?

(编辑:问题的以下部分仍未得到解答,但我已将其移至新问题here,因为它确实是一个完全不同的问题......抱歉提出乱七八糟,没有很好地使用该网站哈哈...)

除此之外,我在类似情况下也遇到了一些捕获转换问题。采用以下类型声明:

C1<? extends C2<?>> c;

与开头的类似声明 a 不同,它在 JDK-8u45 中编译得很好。但是,如果我们检查specification for capture conversion,看来这个声明应该这次会导致编译时错误。

特别是,新类型变量捕获CAP#T 的上限由glb(Bi, Ui[A1:=S1,...,An:=Sn]) 给出,在这种情况下Bi 解析为通配符绑定C2&lt;?&gt;Ui[A1:=S1,...,An:=Sn] 解析为C1&lt;CAP#T&gt;

由此,glb(C2&lt;?&gt;, C1&lt;CAP#T&gt;)解析为交集类型C2&lt;?&gt; &amp; C1&lt;CAP#T&gt;,这是无效的,因为C2&lt;?&gt;C1&lt;CAP#T&gt;都是类类型,不是接口类型,但它们都不是另一个的子类型.

definition of the intersection type 本身更清楚地说明了这种(明显的)违规行为。

我确定这不是一个错误,我只是在某个地方犯了一些简单的错误......但如果这里没有人可以为我解释这一点,我会尝试编译器开发邮件列表或其他东西。

感谢您的帮助!

【问题讨论】:

  • 这是一个有趣的问题。我只是好奇,这是你有一些理论问题还是你有一些现实世界的课程?我无法想象在哪里使用class C1&lt;T extends C1&lt;T&gt;&gt; {}class C2&lt;U&gt; extends C1&lt;C2&lt;U&gt;&gt; {}
  • 有效问题!我没有针对这个特定问题的具体实际应用...但是我确实需要了解正确的预期行为,因为我正在类型系统上编写一堆反射实用程序并想要该行为匹配规范/JDK。目前它大部分都在工作,包括泛型方法调用的类型推断,但是有几个边缘情况(比如这个)会导致问题。如果你想看看它托管在这里:github.com/StrangeSkies/uk.co.strangeskies。还没有 wiki,但 .reflection 包的 javadocs 都存在。
  • 这实际上与捕获转换关系不大。相反,您应该在 4.10.2 和 4.5.1 中寻找答案。只要您认为这与捕获转化有关,您就会被误导。例如,你为什么 C1&lt;? extends C2&lt;?&gt;&gt; 不应该编译的理由是无稽之谈。 (我觉得也是错的,如果被应用了捕获转换我不认为有交集类型,因为capture conversion would not be applied recursively但是我刚醒来所以我有点昏昏沉沉。)跨度>
  • 我知道第一部分与捕获转换无关,但c 的声明却可以。而且我没有递归地应用它,我只将它应用到C&lt;T1,...,Tn&gt; 以提供C&lt;X1,...,Xn&gt;,如第二节所述。 4.5.因为类型参数是一个有上限的通配符,并且类型参数本身也有一个上限,所以得到的上限是这两个边界的交集类型:“如果Ti 是@ 形式的通配符类型参数987654369@,那么Si是一个新类型变量,其上限为glb(Bi, Ui[A1:=S1,...,An:=Sn]),下限为空类型。”
  • 有趣 - IntelliJ 14.1.3 没有显示错误,而 javac 显示。创建了一个IntelliJ bug report

标签: java generics compiler-errors java-8 wildcard


【解决方案1】:


C2&lt;x&gt; extends C1&lt;C2&lt;x&gt;&gt; 对于任何引用类型 x,
不是这样
C2&lt;?&gt; extends C1&lt;C2&lt;?&gt;&gt;

通配符? 不是类型。它是一个类型参数。虽然语法非常具有欺骗性(按设计)。

让我们使用不同的语法 - 如果有任何 1 级通配符,请使用 {} 而不是 &lt;&gt;,例如

List{?},  Map{String, ? extends Number}

{?}的意思是声明一个联合类型

List{? extends Number}  ==  union of List<Number>, List<Integer>, List<Long>, ....

很容易看出,List&lt;Integer&gt;List{? extends Number} 的子类型;
List{? extends Number}List{? extends Object} 的子类型

但是,Foo{?} 不可能是 Foo&lt;x&gt; 的子类型。


在我们的语法中,&lt;&gt; 保留用于将类型变量替换为 types。所以我们写了
List&lt;String&gt;, C2&lt;Integer&gt;等。它们的意思很容易理解——只需将List的源代码中的T替换为String,我们就得到了一个古老的普通类。

    interface List<String>
        String get(int)

这不能用于通配符 - 没有意义

    interface List<?>
        ? get(int)

所以不允许new ArrayList{?}(),或者class MyList implements List{?}

那么,我们如何使用List{?}?我们可以调用哪些方法呢?

当一个表达式的类型是List{?}时,我们知道它是一个对象,对于一些未知的类型List<x>的子类/强>x。这是通配符捕获

obj is a List{?}  =>  obj is a List<x>, where x a subtype of Object.

即使x 的确切类型在编译时未知,我们仍然可以进行替换

    interface List<x>
        x get(int)

所以我们可以理解obj.get(0) 的调用;它返回x,而xObject 的子类型;所以我们可以将返回值分配给Object

【讨论】:

  • 啊,是的,没错,这对我来说有点脑残。非常感谢!关于上限交叉类型的C1&lt;? extends C2&lt;?&gt;&gt; c; 问题有什么想法吗?我认为这可能有点棘手,但也许不是......
  • 我已将问题的第二部分放入一个新问题中,因此我可以将您的答案标记为正确并摆脱所有麻烦,因为第二部分基本上是一个完全独立的问题。新问题在这里:stackoverflow.com/questions/30788366/…
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-04-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-10-02
相关资源
最近更新 更多