Java 当使用不相关的接口类型调用时,编译器为什么选择这个带有类类型参数的泛型方法?
考虑以下两个类和接口:Java 当使用不相关的接口类型调用时,编译器为什么选择这个带有类类型参数的泛型方法?,java,generics,java-8,language-lawyer,javac,Java,Generics,Java 8,Language Lawyer,Javac,考虑以下两个类和接口: 公共类Class1{} 公共类2{} 公共接口接口1{} 如果getInterface1和Interface1与Class2没有关系,为什么对mandatory的第二次调用调用调用了Class2的重载方法 公共类测试{ 公共静态void main(字符串[]args){ Class1=getClass1(); Interface1 Interface1=getInterface1(); 必需(getClass1());//打印“T不是类2” 必需(getInterfac
公共类Class1{}
公共类2{}
公共接口接口1{}
如果getInterface1
和Interface1
与Class2
没有关系,为什么对mandatory
的第二次调用调用调用了Class2
的重载方法
公共类测试{
公共静态void main(字符串[]args){
Class1=getClass1();
Interface1 Interface1=getInterface1();
必需(getClass1());//打印“T不是类2”
必需(getInterface1());//打印“T是类2”
必选(类别1);//打印“T不是类别2”
必需(接口1);//打印“T不是类2”
}
公共静态无效强制(TO){
System.out.println(“T不是类2”);
}
公共静态无效强制(TO){
System.out.println(“T是class2”);
}
公共静态T getClass1(){
返回null;
}
公共静态T getInterface1(){
返回null;
}
}
我知道Java 8和Java 7:
$ /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
使用Java 8(也使用11和13进行了测试):
在Java8中,类型推理规则得到了重大的改进,最显著的是目标类型推理得到了很大的改进。因此,在Java 8之前,方法参数站点没有收到任何推断,默认为擦除类型(
Class1
对于getClass1()
和Interface1
对于getInterface1()
),在Java 8中,推断出最具体的适用类型。jlsforjava8引入了jlsforjava7中缺少的一章
最具体的适用类型是
,其中RequiredClass
是上下文所需的类,BottomInterface
是所有接口的底部类型(包括Interface1
)
注意:每个Java类型都可以表示为SomeClass&SomeInterfaces
。由于RequiredClass
是SomeClass
的子类型,BottomInterface
是someInterface
的子类型,X
是每个Java类型的子类型。因此,X
是一种Java底层类型
X
匹配公共静态无效强制(to)
和公共静态无效强制(to)
方法签名,因为X
是Java底部类型
因此,根据,mandatory(getInterface1())
调用了mandatory()
方法中最具体的重载,即公共静态无效强制(to)
,因为
比
更具体
下面是如何显式指定getInterface1()
type参数,使其返回与publicstaticvoidmandatory(to)
方法签名匹配的结果:
public static <T extends Class2 & Interface1> void helper() {
mandatory(Test.<T>getInterface1()); // prints "T is class2"
}
java: interface expected here
↓
public static <T extends Class1 & C̲l̲a̲s̲s̲2> void helper() {
mandatory(Test.<T>getClass1());
}
一句话:Java中的方法重载带来了如此多的惊喜,在使用时应该非常小心。仅通过类型参数的界来区分两个重载是自找麻烦的,答案的复杂性就证明了这一点。您基本上是要求代码的每个读者在理解代码之前阅读并理解该答案。换言之:如果你的程序在类型推断得到改进时中断了,那么你就不在安全区域。祝你好运
java: interface expected here
↓
public static <T extends Class1 & C̲l̲a̲s̲s̲2> void helper() {
mandatory(Test.<T>getClass1());
}