fro*_*que 10 java generics javac language-lawyer java-8
考虑以下两个类和接口:
public class Class1 {}
public class Class2 {}
public interface Interface1 {}
Run Code Online (Sandbox Code Playgroud)
为什么第二次mandatory调用重载方法与Class2, ifgetInterface1和与Interface1无关Class2?
public class Test {
public static void main(String[] args) {
Class1 class1 = getClass1();
Interface1 interface1 = getInterface1();
mandatory(getClass1()); // prints "T is not class2"
mandatory(getInterface1()); // prints "T is class2"
mandatory(class1); // prints "T is not class2"
mandatory(interface1); // prints "T is not class2"
}
public static <T> void mandatory(T o) {
System.out.println("T is not class2");
}
public static <T extends Class2> void mandatory(T o) {
System.out.println("T is class2");
}
public static <T extends Class1> T getClass1() {
return null;
}
public static <T extends Interface1> T getInterface1() {
return null;
}
}
Run Code Online (Sandbox Code Playgroud)
$ /usr/lib/jvm/java-8-openjdk-amd64/bin/javac -source 1.7 -target 1.7 *java; /usr/lib/jvm/java-8-openjdk-amd64/bin/java Test
warning: [options] bootstrap class path not set in conjunction with -source 1.7
1 warning
T is not class2
T is not class2
T is not class2
T is not class2
Run Code Online (Sandbox Code Playgroud)
使用 Java 8(也用 11 和 13 测试):
$ /usr/lib/jvm/java-8-openjdk-amd64/bin/javac *java; /usr/lib/jvm/java-8-openjdk-amd64/bin/java Test
T is not class2
T is class2
T is not class2
T is not class2
Run Code Online (Sandbox Code Playgroud)
Java 8 中的类型推断规则进行了重大修改,最显着的是目标类型推断得到了很大改进。因此,在 Java 8 之前,方法参数站点没有收到任何推断,默认为擦除类型(Class1forgetClass1()和Interface1for getInterface1()),而在 Java 8 中,会推断出最具体的适用类型。Java 8 的 JLS 引入了新的章节第 18 章。类型推断,这是 Java 7 的 JLS 中缺失的。
最具体的适用类型<T extends Interface1>是<X extends RequiredClass & BottomInterface>,其中RequiredClass是上下文所需的类,BottomInterface是所有接口(包括 )的底层类型Interface1。
注意:每个 Java 类型都可以表示为SomeClass & SomeInterfaces. 因为RequiredClass是 的子类型SomeClass,并且BottomInterface是 的子类型SomeInterfaces,X所以是每个 Java 类型的子类型。因此,X是Java底层类型。
X匹配public static <T> void mandatory(T o)和public static <T extends Class2> void mandatory(T o)方法签名,因为它X是 Java 底层类型。
因此,根据\xc2\xa715.12.2,mandatory(getInterface1())调用最具体的mandatory()方法重载,public static <T extends Class2> void mandatory(T o)因为<T extends Class2>它比 更具体<T>。
以下是如何显式指定getInterface1()类型参数以使其返回与public static <T extends Class2> void mandatory(T o)方法签名匹配的结果:
public static <T extends Class2 & Interface1> void helper() {\n mandatory(Test.<T>getInterface1()); // prints "T is class2"\n}\nRun Code Online (Sandbox Code Playgroud)\n\n最具体的适用类型<T extends Class1>是<Y extends Class1 & BottomInterface>,其中BottomInterface是所有接口的底部类型。
Y匹配方法签名,但它与方法签名public static <T> void mandatory(T o)不匹配,因为不扩展。public static <T extends Class2> void mandatory(T o)YClass2
所以mandatory(getClass1())调用public static <T> void mandatory(T o)方法。
与 with 不同getInterface1(),您不能显式指定getClass1()类型参数以使其返回与public static <T extends Class2> void mandatory(T o)方法签名匹配的结果:
java: interface expected here\n \xe2\x86\x93\npublic static <T extends Class1 & C\xcc\xb2l\xcc\xb2a\xcc\xb2s\xcc\xb2s\xcc\xb22> void helper() {\n mandatory(Test.<T>getClass1());\n}\nRun Code Online (Sandbox Code Playgroud)\n