考虑这些经典的Person多态层次结构...
超接口
public interface Person {
String getName();
interface Builder<P, B extends Builder<P, B>> {
B name(String name);
P build();
}
}
Student.java
public class Student implements Person {
@Override
public String getName() {
...
}
public static class Builder implements Person.Builder<Student, Builder> {
@Override
public Builder name(String name) {
...
}
@Override
public Student build() {
...
}
}
}
Employee.java 我在这里省略了Employee类型,因为它与学生
一样PersonBuilderFactory.java
public class PersonBuilderFactory {
public static <T extends Person.Builder> T getBuilder(T...args) {
if (args.getClass().getComponentType().isAssignableFrom(Student.Builder.class)) {
return (T) new Student.Builder();
} else if (args.getClass().getComponentType().isAssignableFrom(Employee.Builder.class)) {
return (T) new Employee.Builder();
}
throw new RuntimeException("No such builder for other person types");
}
TestInference.java
public class TestInference {
public static void testInference() {
Compile Test 1
// java wants me to infer the type argument
// which will build perfectly fine
Student.Builder studentBuilder1 = PersonBuilderFactory.<Student.Builder>getBuilder();
Employee.Builder employeeBuilder1 = PersonBuilderFactory.<Employee.Builder>getBuilder();
Compile Test 2
// so if i remove those explicit type arguments
// everything still works fine
Student.Builder studentBuilder2 = PersonBuilderFactory.getBuilder(); // this will implicitly get a student builder
Employee.Builder employeeBuilder2 = PersonBuilderFactory.getBuilder(); // this will have an employee builder
Compile Test 3
// Now...
// leaving the argument type NOT inferred and changing the data type
// gives me a compile error which is Im expecting and I want
String someString = PersonBuilderFactory.<Student.Builder>getBuilder();
Compile Test 4
// but when i remove the explicit type argument
// it compiles but this will cause me a specific Verify Error
String someAnotherString = PersonBuilderFactory.getBuilder();
}
}
编译测试 1 有明确的类型参数,java要求我删除(告诉我它以某种方式减少)导致编译测试 2 ,这很正常
编译测试 3 是我期待的
编译测试 4 让我感到困惑,为什么编译器没有在没有Person.Builder( T 扩展Person.Builder)的情况下返回一些东西,当我运行代码时,它会抛出一个验证错误,告诉我我的方法不好,我的问题是为什么编译器没有?但是当我明确指定一个类型参数时,当我声明一个正确的变量数据类型时,它返回一个正确的类型。
我完全很难理解Type Inference,有些问题表明它与Java Compiler Version有关,另一篇帖子说&#34;你只是有一个非常复杂的方法&#34;
非常感谢任何帮助。
答案 0 :(得分:1)
当我运行代码时,它会抛出一个验证错误,告诉我我的方法不好,我的问题是为什么编译器没有?
因为编译器无法确定您做错了什么。
问题是Builder
是一个接口;请注意,如果将Builder
放入类中,则代码根本不会编译。类型推断不会以特殊方式处理String
,因为它是最终类(Chapter 18 of JLS仅提及&#34;最终&#34;在单词& #34;最后&#34 ;;它根本没有提到final
。
所以它允许案例4,因为类似于:
class Something extends String implements Person.Builder {}
就类型推断而言,是可能的。同样,即使没有任何内容延伸<T extends String>
,也允许使用String
。
该行的推断类型是交集类型:
INT#1 extends String,Builder
(我通过编译-Xlint:unchecked
&#39;得到了这个;方便的是,有一个关于未经检查的通用数组创建的警告)
因此似乎是编译器允许的。
但是,在该方法中,args.getClass().getComponentType()
的值为java.lang.String
;这与您的任何条件都不匹配,因此它会触及底部的异常。