我在使用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泛型类型推断有哪些限制?它只解析构造函数或静态方法中提供的类型吗?我还没有找到任何相关文档 .
如果我们不能使用类型推断,这是否意味着该类可能不是类型安全的?
2 回答
当代码太复杂时,泛型类型推断可能会失败,但通常您可以显式指定类型,以便不需要推理 . 链式方法调用有时会导致这种情况 . 它只是意味着你失去了不必自己指定类型的便利 .
通用类型检查是一个单独的概念 . 一般情况下,检查器看不到推断类型(
<>
推断为<String, String>
)和显式类型(代码中写入<String, String>
)之间的区别,无论是哪种方式,您的类都应该是类型安全的 .它在https://docs.oracle.com/javase/specs/jls/se9/html/jls-18.html中有详细记录 . 但问题在于它的详细记录:除非你阅读有关这一主题的论文,否则你不太可能熟悉许多行话 .
对于这种情况,您只需要了解对于类型推断,在
new Builder<>()
之后调用哪种方法并不重要;仅使用构造函数本身的参数(以及目标类型,例如Builder<String, String> b = new Builder<>();
,但在这种情况下,您没有) .没有 .
它们完全不相关 .