Java 中的通用类型推断限制
Generic type inference limits in Java
我在使用 Java 泛型类型推断的项目中遇到以下问题。这是一个类似于我原来的代码示例:
public class BuildableObject<R, S> {
public static class OneParameter<R> { }
public static class TwoParameters<R, S> { }
interface TwoParamInterface<R, S> { }
public static class Implementer<T> implements TwoParamInterface<T, T> {}
private final OneParameter<R> first;
private final OneParameter<S> second;
private final TwoParameters<R, S> third;
private final TwoParamInterface<R, S> fourth;
private BuildableObject(OneParameter<R> first, OneParameter<S> second, TwoParameters<R, S> third, TwoParamInterface<R, S> fourth) {
this.first = first;
this.second = second;
this.third = third;
this.fourth = fourth;
}
public static class Builder<R, S> {
private OneParameter<R> first = null;
private OneParameter<S> second = null;
private TwoParameters<R, S> third = null;
private TwoParamInterface<R, S> fourth = null;
public Builder() {}
public Builder<R, S> first(OneParameter<R> first) {
this.first = first; return this;
}
public Builder<R, S> second(OneParameter<S> second) {
this.second = second; return this;
}
public Builder<R, S> third(TwoParameters<R, S> third) {
this.third = third; return this;
}
public Builder<R, S> fourth(TwoParamInterface<R, S> fourth) {
this.fourth = fourth; return this;
}
public BuildableObject<R, S> build() {
return new BuildableObject<>(first, second, third, fourth);
}
}
public static void main(String... args) {
new Builder<>()
.first(new OneParameter<>())
.second(new OneParameter<>())
.third(new TwoParameters<>())
.fourth(new Implementer<String>())
.build();
}
}
此代码在 new Implementer<String>
处中断,但如果我使用 new Builder<String, String>
而不是 new Builder<>
。
为什么在new Implementer<String>
中指定了R和S的类型,为什么Java不能推断出Builder的类型是Builder<String, String>
?
Java 泛型类型推断的限制是什么?它只解析构造函数或静态方法中提供的类型吗?我还没有找到这方面的任何文档。
这是否意味着如果我们不能使用类型推断,这个 class 可能不是类型安全的?
在 https://docs.oracle.com/javase/specs/jls/se9/html/jls-18.html 中有详细记录。但问题是它详细记录:有很多行话你不太可能熟悉,除非你阅读关于这个主题的论文。
对于这种情况,您只需要了解对于类型推断,在 new Builder<>()
之后调用什么方法并不重要;仅使用构造函数本身的参数(以及目标类型,例如 Builder<String, String> b = new Builder<>();
,但在本例中您没有)。
Does it only resolve types provided in constructors or static methods?
没有
Does this mean in any way that this class might not be type safe if we can't use type inference?
他们完全没有关系。
当代码太复杂时,通用类型推断可能会失败,但通常您可以显式指定类型,这样就不需要推断了。链式方法调用有时会导致这种情况。这只是意味着您失去了不必自己指定类型的便利。
通用类型检查是一个单独的概念。一般来说,检查器看不出推断类型(<>
推断为 <String, String>
)和显式类型(<String, String>
写在代码中)之间的区别,无论哪种方式它都会检查该对象仅使用字符串。只要编译器不报错,你的 class 应该是类型安全的。
我在使用 Java 泛型类型推断的项目中遇到以下问题。这是一个类似于我原来的代码示例:
public class BuildableObject<R, S> {
public static class OneParameter<R> { }
public static class TwoParameters<R, S> { }
interface TwoParamInterface<R, S> { }
public static class Implementer<T> implements TwoParamInterface<T, T> {}
private final OneParameter<R> first;
private final OneParameter<S> second;
private final TwoParameters<R, S> third;
private final TwoParamInterface<R, S> fourth;
private BuildableObject(OneParameter<R> first, OneParameter<S> second, TwoParameters<R, S> third, TwoParamInterface<R, S> fourth) {
this.first = first;
this.second = second;
this.third = third;
this.fourth = fourth;
}
public static class Builder<R, S> {
private OneParameter<R> first = null;
private OneParameter<S> second = null;
private TwoParameters<R, S> third = null;
private TwoParamInterface<R, S> fourth = null;
public Builder() {}
public Builder<R, S> first(OneParameter<R> first) {
this.first = first; return this;
}
public Builder<R, S> second(OneParameter<S> second) {
this.second = second; return this;
}
public Builder<R, S> third(TwoParameters<R, S> third) {
this.third = third; return this;
}
public Builder<R, S> fourth(TwoParamInterface<R, S> fourth) {
this.fourth = fourth; return this;
}
public BuildableObject<R, S> build() {
return new BuildableObject<>(first, second, third, fourth);
}
}
public static void main(String... args) {
new Builder<>()
.first(new OneParameter<>())
.second(new OneParameter<>())
.third(new TwoParameters<>())
.fourth(new Implementer<String>())
.build();
}
}
此代码在 new Implementer<String>
处中断,但如果我使用 new Builder<String, String>
而不是 new Builder<>
。
为什么在new Implementer<String>
中指定了R和S的类型,为什么Java不能推断出Builder的类型是Builder<String, String>
?
Java 泛型类型推断的限制是什么?它只解析构造函数或静态方法中提供的类型吗?我还没有找到这方面的任何文档。
这是否意味着如果我们不能使用类型推断,这个 class 可能不是类型安全的?
在 https://docs.oracle.com/javase/specs/jls/se9/html/jls-18.html 中有详细记录。但问题是它详细记录:有很多行话你不太可能熟悉,除非你阅读关于这个主题的论文。
对于这种情况,您只需要了解对于类型推断,在 new Builder<>()
之后调用什么方法并不重要;仅使用构造函数本身的参数(以及目标类型,例如 Builder<String, String> b = new Builder<>();
,但在本例中您没有)。
Does it only resolve types provided in constructors or static methods?
没有
Does this mean in any way that this class might not be type safe if we can't use type inference?
他们完全没有关系。
当代码太复杂时,通用类型推断可能会失败,但通常您可以显式指定类型,这样就不需要推断了。链式方法调用有时会导致这种情况。这只是意味着您失去了不必自己指定类型的便利。
通用类型检查是一个单独的概念。一般来说,检查器看不出推断类型(<>
推断为 <String, String>
)和显式类型(<String, String>
写在代码中)之间的区别,无论哪种方式它都会检查该对象仅使用字符串。只要编译器不报错,你的 class 应该是类型安全的。