Общие ограничения вывода типов в Java - PullRequest
0 голосов
/ 23 мая 2018

В моем проекте я сталкиваюсь со следующей проблемой, связанной с выводом типа универсальных элементов 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<>.

ПочемуJava не может сделать вывод, что тип Builder равен Builder<String, String>, если типы R и S указаны в new Implementer<String>?

Каковы пределы вывода универсальных типов Java?Разрешает ли он только типы, предоставленные в конструкторах или статических методах?Я не нашел никакой документации по этому вопросу.

Означает ли это каким-либо образом, что этот класс может быть небезопасным, если мы не можем использовать вывод типов?

Ответы [ 2 ]

0 голосов
/ 23 мая 2018

Вывод общего типа может завершиться ошибкой, если код слишком сложен, но обычно вы можете явно указать типы, чтобы вывод не был необходим.Цепные вызовы методов могут иногда вызывать это.Это просто означает, что вы теряете удобство отсутствия необходимости указывать тип самостоятельно.

Общий тип проверка - это отдельная концепция.Обычно средство проверки не видит разницы между выведенным типом (<>, выведенным как <String, String>) и явным типом (<String, String>, записанным в коде), так или иначе, он будет проверять, используются ли только строки с этимобъект.Пока компилятор не жалуется, ваш класс должен быть безопасным для типов.

0 голосов
/ 23 мая 2018

Подробно задокументировано https://docs.oracle.com/javase/specs/jls/se9/html/jls-18.html. Но проблема в том, что подробно задокументировано : существует много жаргона, с которым вы вряд ли будете знакомы, если не будете читать статьи на эту тему.

В этом случае вам просто нужно понять, что для вывода типов не имеет значения, какие методы вы вызываете после new Builder<>();используются только параметры самого конструктора (и целевой тип, например, в Builder<String, String> b = new Builder<>();, но в этом случае у вас его нет).

Разрешает ли он только типы, предоставленные в конструкторах или статическихметоды?

Нет.

Означает ли это каким-либо образом, что этот класс может быть небезопасным, если мы не можем использовать вывод типов?

Они совершенно не связаны.

...