Параметр ограничения Java для общего суперкласса - PullRequest
7 голосов
/ 16 июня 2019

Мотивация

У меня есть класс Either<L, R>, который представляет значение одного из двух типов или семантически различных состояний. В некоторых случаях полезно работать с ним независимо от того, какое значение имеет альтернатива.

Задача

Я хочу (нестатический) метод, который принимает Consumer<T>, где T является супертипом L и R, где L и R являются параметрами типа для класса .
В настоящее время Java позволяет мне делать это: (статическая реализация)

public static <T, L extends T, R extends T> void collapse(Either<L,R> e, Consumer<T> op)

Но, конечно, в нестатической реализации я не могу наложить ограничения на L и R, потому что они уже определены для рассматриваемого экземпляра. Вместо этого мне нужно, чтобы эти ограничения были наложены на T, но java не позволит мне написать следующее, потому что он допускает только один класс в ограничении супертипа или подтипа одновременно. Это особенно расстраивает, учитывая, что все классы имеют как минимум Object в качестве общего супертипа, поэтому эти ограничения всегда выполняются.

public void collapse(Consumer<? super L & R> op)

Есть ли другой способ определения этого ограничения, любой намек на то, что он разрешен в более поздней версии java, или какое-либо объяснение того, почему это будет нарушающая функция?

Ответы [ 2 ]

4 голосов
/ 16 июня 2019

В вашей статической версии, поскольку вам нужно, чтобы потребитель мог принимать тип "L" или "R", вам на самом деле не нужны переменные типа: Either<? extends T, ? extends T> e.

Но помимо этого, я бы сказал, что ваша статическая версия - действительно лучшее, что вы можете сделать. У Java просто нет особенно выразительной системы типов.

Я не думаю, что ответ Эрана является особенно хорошим решением (с уважением), потому что:

  1. он запекает границу для потребителя: вы должны использовать ту границу, которую вы когда-либо ожидали, и если вы просто не используете Object (что раздражающе обширно), вы всегда найдете случай, когда захотите это было чуть-чуть более разрешительным;
  2. он вводит дополнительный параметр типа везде вы используете тип Either, даже если вам не нужно использовать потребителя, потому что вы всегда должны предоставлять 3 параметра типа (даже если они ?). Третий тип параметра просто ощущается как Cruft.

Единственный реальный недостаток, который я вижу в статической версии, это слегка неловкое соглашение о вызовах: Either.collapse(anEither, aConsumer) в отличие от anEither.collapse(aConsumer). Конечно, первое немного более многословно ... но оно делает то, что вы хотите, так что вам, возможно, придется просто принять неловкость.

2 голосов
/ 16 июня 2019

Возможно, вам следует добавить T в качестве параметра третьего типа вашего класса:

class Either<T, L extends T, R extends T>
{
    public void collapse(Consumer<T> op) {

    }
}
...