Java 泛型行为在JDK 8和JDK 9中有所不同
下面的简单类(复制它):Java 泛型行为在JDK 8和JDK 9中有所不同,java,generics,java-8,java-9,java-10,Java,Generics,Java 8,Java 9,Java 10,下面的简单类(复制它): import static org.hamcrest.*; 导入静态org.junit.Assert.assertThat; 导入java.util.*; 导入org.junit.Test; 公共类测试泛型{ @试验 public void thishouldcomile(){ List myList=Arrays.asList(“a”、“b”、“c”); 资产(“列表不包含意外元素”),myList,而不是(任何一项(hasItem(“d”)、hasItem(“e”)
import static org.hamcrest.*;
导入静态org.junit.Assert.assertThat;
导入java.util.*;
导入org.junit.Test;
公共类测试泛型{
@试验
public void thishouldcomile(){
List myList=Arrays.asList(“a”、“b”、“c”);
资产(“列表不包含意外元素”),myList,而不是(任何一项(hasItem(“d”)、hasItem(“e”)、hasItem(“f”));
}
}
行为取决于JDK版本:
- 在JDK中正确编译经过一些研究后,我相信我们可以将其排除在Junit或hamcrest问题之外。事实上,这似乎是一个JDK错误。以下代码不会在JDK>8中编译:
将其图灵到不使用库的MCVE中:AnyOf<Iterable<? super String>> matcher = CoreMatchers.anyOf( CoreMatchers.hasItem("d"), CoreMatchers.hasItem("e"), CoreMatchers.hasItem("f"));
就像您介绍的案例一样,将执行分解为多行将产生正确的结果:class Test { class A<S> { } class B<S> { } class C<S> { } class D { } <T> A<B<? super T>> foo() { return null; } <U> C<U> bar(A<U> a1, A<? super U> a2) { return null; } C<B<? super D>> c = bar(foo(), foo()); }
A<B<? super D>> a1 = foo(); A<B<? super D>> a2 = foo(); C<B<? super D>> c = bar(a1, a2);
A我创建了一个不同的MCVE,显示了类型推断的差异:
打电话的时候import java.util.Arrays; import java.util.List; public class Example { public class Matcher<T> { private T t; public Matcher(T t) { this.t = t; } } public <N> Matcher<N> anyOf(Matcher<N> first, Matcher<? super N> second) { return first; } public <T> Matcher<List<? super T>> hasItem1(T item) { return new Matcher<>(Arrays.asList(item)); } public <T> Matcher<List<? super T>> hasItem2(T item) { return new Matcher<>(Arrays.asList(item)); } public void thisShouldCompile() { Matcher x = (Matcher<List<? super String>>) anyOf(hasItem1("d"), hasItem2("e")); } }
anyOf(Matcher<List<? super String>>, Matcher<List<? super String>>)
anyOf(MatcherIt在我看来确实像个bug。在JDK 9中编译泛型代码似乎有很多修复:……而
中的junit:4.12
类是用Java5(类版本49.0)编译的……如果这可能导致任何线索的话:)如果我们能够追踪到JLS,最好是一个具体的更改或错误号,那就太好了。@tkruse您是否获得了公共ID?向Oracle报告说,老实说,我相信编译器中有一个错误是很明显的,但是将它链接到JLS会很有趣,可以准确指出编译器的错误所在(或者,如果JLS中发生了导致它的变化)。我将为您的研究颁发奖金,尽管我认为要真正解决这个问题还有很多工作要做。让我们看看@tkruse的bug报告发生了什么。@Didierr感谢您的奖金。我曾尝试查看JLS规范中的类型推断部分,以了解差异,但我没有发现任何对我来说是显而易见的指出这方面的规则应该是不同的,我没有足够的知识通过单独遵循JLS规则来手动验证此代码。我确实注意到与8相比有一些新的部分,特别是有一个注释:@didierr在各种特殊情况下,基于B2中出现的边界,我们急切地解决了一个推论作为调用的返回类型出现的变量。这是为了避免通常的约束èRθ→ T›不是保持完整性的。不幸的是,通过急切地解析变量,我们可能无法利用稍后将推断的边界。Assert
class Test { class A<S> { } class B<S> { } class C<S> { } class D { } <T> A<B<? super T>> foo() { return null; } <U> C<U> bar(A<U> a1, A<? super U> a2) { return null; } C<B<? super D>> c = bar(foo(), foo()); }
class Test { class A<S> { } class B<S> { } class C<S> { } class D { } <T> A<B<? super T>> foo() { return null; } <U> C<U> bar(A<? super U> a) { return null; } C<B<? super D>> c = bar(foo()); }
Error:(21, 28) java: incompatible types: inference variable U has incompatible bounds equality constraints: com.Test.B<? super com.Test.D> upper bounds: com.Test.B<? super capture#1 of ? super com.Test.D>,java.lang.Object
// This causes compile to succeed even though an IDE will call it redundant C<B<? super D>> c = bar(this.<D>foo(), this.<D>foo());
A<B<? super D>> a1 = foo(); A<B<? super D>> a2 = foo(); C<B<? super D>> c = bar(a1, a2);
import java.util.Arrays; import java.util.List; public class Example { public class Matcher<T> { private T t; public Matcher(T t) { this.t = t; } } public <N> Matcher<N> anyOf(Matcher<N> first, Matcher<? super N> second) { return first; } public <T> Matcher<List<? super T>> hasItem1(T item) { return new Matcher<>(Arrays.asList(item)); } public <T> Matcher<List<? super T>> hasItem2(T item) { return new Matcher<>(Arrays.asList(item)); } public void thisShouldCompile() { Matcher x = (Matcher<List<? super String>>) anyOf(hasItem1("d"), hasItem2("e")); } }
Example.java:27: error: incompatible types: Example.Matcher<List<? super Object>> cannot be converted to Example.Matcher<List<? super String>> Matcher x = (Matcher<List<? super String>>) anyOf(hasItem1("d"), hasItem2("e"));
Matcher<N> anyOf(Matcher<N> first, Matcher<? super N> second)
anyOf(Matcher<List<? super String>>, Matcher<List<? super String>>)