Типы аргументов для передачина Яве - PullRequest
2 голосов
/ 03 октября 2019

В главе 8 Общих типов из Core Java Volume I Edition 10,

ПРИМЕЧАНИЕ. Еще одним распространенным использованием границ супертипа является тип аргумента функционального интерфейса. Например, интерфейс Collection имеет метод

default boolean removeIf(Predicate<? super E> filter)

Метод удаляет все элементы, которые удовлетворяют данному предикату. Например, если вы ненавидите сотрудников с нечетными хэш-кодами, вы можете удалить их следующим образом:

ArrayList<Employee> staff = . . .; Predicate<Object> oddHashCode = obj -> obj.hashCode() %2 != 0; staff.removeIf(oddHashCode);

Вы хотите, чтобы можно было передавать Predicate<Object>, а не просто Predicate<Employee>. Супер подстановочный знак делает это возможным.

При попытке понять это я столкнулся с некоторыми проблемами, поэтому <? super E> означает, что фильтр может указывать на любой тип предиката, который может быть суперклассом Employee или * 1021. * сам.

В вышеприведенном тексте мы можем передать Predicate<Object> Predicate<? super E>.

Но что, если Predicate<? super E> указывает на Predicate<Employee>, можно ли передать Predicate<Object> на Predicate<Employee>?

Я что-то неправильно понял?

1 Ответ

2 голосов
/ 03 октября 2019

Ваше понимание верно. Например, функция, которая принимает Predicate<? super Employee> (как в вашем примере ArrayList<Employee>), также может принимать Predicate<Object> подобно Objects::nonNull. Концептуально это имеет смысл по следующей причине: «Мы (класс) берем Predicate, который действует на нас или на любой из (переходных) суперклассов нашего самого себя, потому что у нас есть is-a отношения с этими суперклассами. "То есть функция, которая принимает любой Object и возвращает boolean, эквивалентно применима к Employee, потому что Employee is-a Object, и поэтому ее можно применятьэта функция для Employee. Производный класс не является точно таким же, как базовый класс, но предикат (логический тест) по-прежнему применяется к производному классу, поскольку имеет смысл говорить о производном классе как о базовом классе.

Давайте рассмотрим пример: Employees может быть получено из Person. Если Person можно протестировать с помощью Predicate<Person>, называемого hasJob, то логично также иметь возможность проверить Employees для hasJob. Способность этой функции принимать Predicate<? super Employee> вместо Predicate<Employee> требуется для поддержания способности функции принимать логически обоснованный предикат. С другой стороны, если вы ожидаете, что Employee s будет проверено только для некоторого свойства, вы можете вместо этого принять только Predicate<Employee>, поскольку это соответствует логической обоснованности только Employee и его производных классов, обладающих способностьюбыть проверенным на это свойство.

Чтобы быть на 100% ясным о том, что здесь происходит:

  • Predicate<? super Employee> принимает Predicate, что test s Employee и любой суперкласс из Employee, , включая Object
  • Predicate<Employee> принимает Predicate, что test s Employee и любой подкласс из Employee, который исключает Object

Учитывая эту иерархию классов: SalariedEmployee is-a Employee is-a Person, вот что происходит (P - сокращение для Predicate):

╔══════════════════╦═══════════╦═══════════════════╦═════════════╦═════════════════════╦═════════════════════╦═════════════════════════════╗
║       Type       ║ P<Person> ║ P<? super Person> ║ P<Employee> ║ P<? super Employee> ║ P<SalariedEmployee> ║ P<? super SalariedEmployee> ║
╠══════════════════╬═══════════╬═══════════════════╬═════════════╬═════════════════════╬═════════════════════╬═════════════════════════════╣
║ Person           ║ Accept    ║ Accept            ║ Reject      ║ Accept              ║ Reject              ║ Accept                      ║
║ Employee         ║ Accept    ║ Reject            ║ Accept      ║ Accept              ║ Reject              ║ Accept                      ║
║ SalariedEmployee ║ Accept    ║ Reject            ║ Accept      ║ Reject              ║ Accept              ║ Accept                      ║
║ Object           ║ Reject    ║ Accept            ║ Reject      ║ Accept              ║ Reject              ║ Accept                      ║
╚══════════════════╩═══════════╩═══════════════════╩═════════════╩═════════════════════╩═════════════════════╩═════════════════════════════╝

Обратите внимание, что Accept/Reject обозначает типы, которые можно вводить в Predicate, а не фактический результат Predicate.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...