简体   繁体   English

Java中的泛型类型推断限制

[英]Generic type inference limits in Java

I'm facing the following problem in my project with Java generics type inference. 我在使用Java泛型类型推断的项目中面临以下问题。 This is a code sample that's similar to my original one: 这是一个与我原始代码类似的代码示例:

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();
  }
}

This code breaks at new Implementer<String> , but works if I use new Builder<String, String> instead of new Builder<> . 此代码在new Implementer<String>处中断,但如果我使用new Builder<String, String>而不是new Builder<> new Builder<String, String>则会有效。

Why can't Java infer that the type of the Builder is Builder<String, String> if the types of R and S are specified in new Implementer<String> ? 如果在new Implementer<String>中指定了R和S的类型,为什么Java不能推断Builder的类型是Builder<String, String> new Implementer<String>

What are the limits of Java generic types inference? Java泛型类型推断有哪些限制? Does it only resolve types provided in constructors or static methods? 它只解析构造函数或静态方法中提供的类型吗? I haven't found any documentation on this. 我还没有找到任何相关文档。

Does this mean in any way that this class might not be type safe if we can't use type inference? 如果我们不能使用类型推断,这是否意味着该类可能不是类型安全的?

It's documented in detail in https://docs.oracle.com/javase/specs/jls/se9/html/jls-18.html . 它在https://docs.oracle.com/javase/specs/jls/se9/html/jls-18.html中有详细记录。 But the problem is that it's documented in detail : there is a lot of jargon you are unlikely to be familiar with unless you read papers on this subject. 但问题在于它的详细记录 :除非你阅读有关这一主题的论文,否则你不太可能熟悉许多行话。

For this case you just need to understand that for type inference it doesn't matter what methods you call after new Builder<>() ; 对于这种情况,您只需要了解对于类型推断,在new Builder<>()之后调用哪种方法并不重要; only parameters to the constructor itself are used (and a target type eg in Builder<String, String> b = new Builder<>(); , but in this case you don't have one). 仅使用构造函数本身的参数(以及目标类型,例如在Builder<String, String> b = new Builder<>();但在这种情况下,您没有)。

Does it only resolve types provided in constructors or static methods? 它只解析构造函数或静态方法中提供的类型吗?

No. 没有。

Does this mean in any way that this class might not be type safe if we can't use type inference? 如果我们不能使用类型推断,这是否意味着该类可能不是类型安全的?

They are completely unrelated. 它们完全不相关。

Generic type inference can fail when the code is too complicated, but usually you can explicitly specify the types so that inference isn't necessary. 当代码太复杂时,泛型类型推断可能会失败,但通常您可以显式指定类型,以便不需要推理。 Chained method calls can cause this sometimes. 链式方法调用有时会导致这种情况。 It just means you lose the convenience of not having to specify the type yourself. 它只是意味着你失去了不必自己指定类型的便利。

Generic type checking is a separate concept. 通用类型检查是一个单独的概念。 Generally the checker doesn't see a difference between an inferred type ( <> inferred as <String, String> ) and an explicit type ( <String, String> written in the code), either way it's going to check that only strings are used with that object. 通常,检查器看不到推断类型( <>推断为<String, String> )和显式类型( <String, String>在代码中编写)之间的区别,无论是哪种方式,它都要检查只有字符串是与该对象一起使用。 As long as the compiler doesn't complain, your class should be type-safe. 只要编译器没有抱怨,您的类应该是类型安全的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM