【问题标题】:Generic type inference limits in JavaJava 中的泛型类型推断限制
【发布时间】:2018-05-23 12:07:15
【问题描述】:

我在使用 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&lt;String&gt; 处中断,但如果我使用new Builder&lt;String, String&gt; 而不是new Builder&lt;&gt; 则有效。

如果new Implementer&lt;String&gt;中指定了R和S的类型,为什么Java不能推断出Builder的类型是Builder&lt;String, String&gt;

Java 泛型类型推断的限制是什么?它是否只解析构造函数或静态方法中提供的类型?我还没有找到任何关于此的文档。

这是否意味着如果我们不能使用类型推断,这个类可能不是类型安全的?

【问题讨论】:

    标签: java generics types type-inference


    【解决方案1】:

    https://docs.oracle.com/javase/specs/jls/se9/html/jls-18.html 中有详细记录。但问题是它的文档详细:除非您阅读有关此主题的论文,否则您不太可能熟悉很多行话。

    对于这种情况,您只需要了解对于类型推断,您在new Builder&lt;&gt;() 之后调用什么方法并不重要;仅使用构造函数本身的参数(以及目标类型,例如Builder&lt;String, String&gt; b = new Builder&lt;&gt;();,但在这种情况下您没有)。

    它是否只解析构造函数或静态方法中提供的类型?

    没有。

    这是否意味着如果我们不能使用类型推断,这个类可能不是类型安全的?

    它们完全不相关。

    【讨论】:

    • 您说推理只使用传递给构造函数的参数,但对第二个问题回答否。您的意思是它不适用于静态方法,还是类型推断可以通过其他一些方法来解析与这种情况无关的类型?
    • 我的意思是它适用于实例方法的方式与其他地方相同,但这与这种情况无关,因为您的实例方法没有类型参数,并且没有什么可以推断的他们。
    • 您希望它使用实例方法的arguments 来确定receiver 的类型。据我了解(可能不完整;您可以看到规范非常复杂)这是不允许的。
    【解决方案2】:

    当代码过于复杂时,泛型类型推断可能会失败,但通常您可以显式指定类型,这样就不需要推断。链式方法调用有时会导致这种情况。这只是意味着您失去了不必自己指定类型的便利。

    泛型类型检查 是一个单独的概念。通常,检查器不会看到推断类型(&lt;&gt; 推断为&lt;String, String&gt;)和显式类型(代码中编写的&lt;String, String&gt;)之间的区别,无论哪种方式,它都会检查是否只使用了字符串目的。只要编译器不抱怨,你的类就应该是类型安全的。

    【讨论】:

    • "但您始终可以显式指定类型,这样就不需要推断" 并非总是如此,推断的类型可以是不可命名的(例如匿名类或通配符捕获)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-04-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-28
    • 2015-07-04
    • 1970-01-01
    相关资源
    最近更新 更多