测试 Java 6 和 Java 8 中的类型匹配差异
Testing type matching differences in Java 6 and Java 8
我将应用程序 JDK 从 1.6 更新到 1.8,但我在 IntelliJ 中保持语言级别 1.6。
更新后,我在检查对象类型的 assertThat
语句中的某些测试中遇到编译错误。代码是这样的:
assertThat((Class) myList.get(0).getMyClassType(), is(equalTo(MySubclass.class)));
myList 看起来像这样:
List<MyClassDefinition> myList = myClassDefinition.getMyClassDefinitions(reader);
MyClassDefinition 和 getMyClassType() 的定义是这样的:
public class MyClassDefinition {
private Class<? extends MyClass> classType;
public Class<? extends MyClass> getMyClassType() {
return classType;
}
}
而 MySubclass 是 Myclass 的子class:
public class MySubclass extends MyClass {
@Override
public void initialise() {
// some action here!
}
}
MyClass的定义是
public abstract class MyClass extends AnotherClass<AnotherType>{
//Definitions
}
Assert is and equals 库的导入是这样的:
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
并且 hamcrest 版本是 hamcrest-all-1-3
将项目 SDK 更改为 jdk 1.8 后,我收到此错误消息:
Error:(136, 9) java: no suitable method found for assertThat(java.lang.Class,org.hamcrest.Matcher<java.lang.Class<MySubClass>>)
method org.hamcrest.MatcherAssert.assertThat(java.lang.String,boolean) is not applicable
(argument mismatch; java.lang.Class cannot be converted to java.lang.String)
method org.hamcrest.MatcherAssert.<T>assertThat(java.lang.String,T,org.hamcrest.Matcher<? super T>) is not applicable
(cannot infer type-variable(s) T
(actual and formal argument lists differ in length))
method org.hamcrest.MatcherAssert.<T>assertThat(T,org.hamcrest.Matcher<? super T>) is not applicable
(cannot infer type-variable(s) T
(argument mismatch; org.hamcrest.Matcher<java.lang.Class<MySubClass>> cannot be converted to org.hamcrest.Matcher<? super java.lang.Class>))
应用程序是用 Ant 构建的,我们已将 hamcrest jar 文件添加到 class 文件,因此当我们在项目中更改 JDK 时没有变化。
所以我的问题是,为什么当我使用相同级别的语言 (1.6) 进行编译时,这段代码可以使用 JDK 1.6 而不能使用 1.8?它是否取决于不同的库?
显然,您通过将类型转换插入 原始类型 Class
解决了泛型类型签名问题,这导致编译器将整个语句视为仅使用 原始类型 的 未检查 操作。
正如您从编译器消息中看到的那样,org.hamcrest.Matcher<java.lang.Class<MySubClass>> cannot be converted to org.hamcrest.Matcher<? super java.lang.Class>
,它现在进行了泛型类型检查(正确地)失败了,但是恕我直言,它不应该在 Java 下进行类型检查6 语言规则。问题源于 JDK8 不包含原始 Java 6 编译器,而是让新编译器尝试使用旧规则进行编译,这可能不那么精确。
但无论行为是否正确,我都不希望对其进行修复,因为模仿旧的 Java 6 语言规则不是高优先级。
请注意,使用源代码级别 1.8,即使没有 原始类型 转换,代码编译也没有问题。最初的问题源于 CoreMatchers.equalTo(…)
的限制性签名。传递给 assertThat
的独立表达式 equalTo(InstanceOfFoo)
returns a Matcher<Foo>
只允许测试 Foo
的实例(使用 [=18= 时更糟] 也只能测试 Foo
的实例,这使得测试毫无意义)。
对于 Java 8,有目标类型推断,这允许,例如
Matcher<Object> m = equalTo(InstanceOfFoo);
,这将为 <T>
推断出 Object
并通过,因为 InstanceOfFoo
也可以分配给 Object
。这也可以与您问题的复合 assertThat
语句结合使用,从而推断出合适的类型。
这引导我们找到适用于所有语言级别的通用解决方案。只需使用
assertThat(myList.get(0).getMyClassType(), is(equalTo((Object)MySubclass.class)));
Class<MySubclass>
当然可以分配给 Object
这使得转换成为空操作。但是,得到一个 Matcher<Object>
,你可以检查每个你喜欢的对象,包括 myList.get(0).getMyClassType()
的结果,当然,它也可以分配给 Object
。与您最初的解决方法不同,这不支持任何 原始类型 用法,也不支持 未检查 操作。
您也可以使用显式类型而不是强制转换,CoreMatchers.<Object>equalTo(MySubclass.class)
,但这会消除 import static
的好处。
顺便说一句,在匹配Class
个对象时,您可以使用sameInstance
代替equalTo
。
我将应用程序 JDK 从 1.6 更新到 1.8,但我在 IntelliJ 中保持语言级别 1.6。
更新后,我在检查对象类型的 assertThat
语句中的某些测试中遇到编译错误。代码是这样的:
assertThat((Class) myList.get(0).getMyClassType(), is(equalTo(MySubclass.class)));
myList 看起来像这样:
List<MyClassDefinition> myList = myClassDefinition.getMyClassDefinitions(reader);
MyClassDefinition 和 getMyClassType() 的定义是这样的:
public class MyClassDefinition {
private Class<? extends MyClass> classType;
public Class<? extends MyClass> getMyClassType() {
return classType;
}
}
而 MySubclass 是 Myclass 的子class:
public class MySubclass extends MyClass {
@Override
public void initialise() {
// some action here!
}
}
MyClass的定义是
public abstract class MyClass extends AnotherClass<AnotherType>{
//Definitions
}
Assert is and equals 库的导入是这样的:
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
并且 hamcrest 版本是 hamcrest-all-1-3
将项目 SDK 更改为 jdk 1.8 后,我收到此错误消息:
Error:(136, 9) java: no suitable method found for assertThat(java.lang.Class,org.hamcrest.Matcher<java.lang.Class<MySubClass>>)
method org.hamcrest.MatcherAssert.assertThat(java.lang.String,boolean) is not applicable
(argument mismatch; java.lang.Class cannot be converted to java.lang.String)
method org.hamcrest.MatcherAssert.<T>assertThat(java.lang.String,T,org.hamcrest.Matcher<? super T>) is not applicable
(cannot infer type-variable(s) T
(actual and formal argument lists differ in length))
method org.hamcrest.MatcherAssert.<T>assertThat(T,org.hamcrest.Matcher<? super T>) is not applicable
(cannot infer type-variable(s) T
(argument mismatch; org.hamcrest.Matcher<java.lang.Class<MySubClass>> cannot be converted to org.hamcrest.Matcher<? super java.lang.Class>))
应用程序是用 Ant 构建的,我们已将 hamcrest jar 文件添加到 class 文件,因此当我们在项目中更改 JDK 时没有变化。 所以我的问题是,为什么当我使用相同级别的语言 (1.6) 进行编译时,这段代码可以使用 JDK 1.6 而不能使用 1.8?它是否取决于不同的库?
显然,您通过将类型转换插入 原始类型 Class
解决了泛型类型签名问题,这导致编译器将整个语句视为仅使用 原始类型 的 未检查 操作。
正如您从编译器消息中看到的那样,org.hamcrest.Matcher<java.lang.Class<MySubClass>> cannot be converted to org.hamcrest.Matcher<? super java.lang.Class>
,它现在进行了泛型类型检查(正确地)失败了,但是恕我直言,它不应该在 Java 下进行类型检查6 语言规则。问题源于 JDK8 不包含原始 Java 6 编译器,而是让新编译器尝试使用旧规则进行编译,这可能不那么精确。
但无论行为是否正确,我都不希望对其进行修复,因为模仿旧的 Java 6 语言规则不是高优先级。
请注意,使用源代码级别 1.8,即使没有 原始类型 转换,代码编译也没有问题。最初的问题源于 CoreMatchers.equalTo(…)
的限制性签名。传递给 assertThat
的独立表达式 equalTo(InstanceOfFoo)
returns a Matcher<Foo>
只允许测试 Foo
的实例(使用 [=18= 时更糟] 也只能测试 Foo
的实例,这使得测试毫无意义)。
对于 Java 8,有目标类型推断,这允许,例如
Matcher<Object> m = equalTo(InstanceOfFoo);
,这将为 <T>
推断出 Object
并通过,因为 InstanceOfFoo
也可以分配给 Object
。这也可以与您问题的复合 assertThat
语句结合使用,从而推断出合适的类型。
这引导我们找到适用于所有语言级别的通用解决方案。只需使用
assertThat(myList.get(0).getMyClassType(), is(equalTo((Object)MySubclass.class)));
Class<MySubclass>
当然可以分配给 Object
这使得转换成为空操作。但是,得到一个 Matcher<Object>
,你可以检查每个你喜欢的对象,包括 myList.get(0).getMyClassType()
的结果,当然,它也可以分配给 Object
。与您最初的解决方法不同,这不支持任何 原始类型 用法,也不支持 未检查 操作。
您也可以使用显式类型而不是强制转换,CoreMatchers.<Object>equalTo(MySubclass.class)
,但这会消除 import static
的好处。
顺便说一句,在匹配Class
个对象时,您可以使用sameInstance
代替equalTo
。