Java 8 нижний ограниченный подстановочный знак - PullRequest
4 голосов
/ 19 июня 2019

Я готовлюсь к сертификату OCP и натолкнулся на идею подстановочного знака с нижним ограничением. Если я правильно понимаю, подстановочный знак с нижним ограничением используется, когда мы хотим, чтобы Java знала, что «ограниченный тип» всегда можно добавить в нашу универсальную коллекцию.

Например:

public static void addInteger(List<? super Integer> list, Integer i)
{
    list.add(i);
}


public static void main(String[] args)
{   
    List<Number> list = new ArrayList<>();
    addInteger(list, 100);
    addInteger(list, 200);
    System.out.println(list);       // [100,200]

}

Поскольку "? Super Integer" указывает, что тип должен быть Integer или его суперклассом, добавление Integer в список будет работать в каждом случае.

Однако этот код все еще компилируется и работает как обычно:

public static void main(String[] args)
{   
    Predicate<? super String> pred = s -> s.startsWith("M"); // still compiles
    System.out.println(pred.test("Mon")); // Output true

}

Теперь у нас есть предикат, который будет принимать 1 параметр, который является строкой или ее суперклассом, но мы не уверены, что это на самом деле строка или нет (что, если это просто объект?). Однако мы все равно можем получить доступ к методу startsWith(), например, s на самом деле является строкой.

Почему это происходит? Пожалуйста, объясните мне.

Ответы [ 2 ]

7 голосов
/ 19 июня 2019

Predicate<? super String> pred можно присвоить либо Predicate<String>, либо Predicate<Object>. Вы присваиваете ему Predicate<String>, что разрешено. Компилятор делает вывод, что s -> s.startsWith("M") является Predicate<String>, поскольку вы используете метод String в лямбда-выражении.

Например, следующее также пройдет компиляцию:

Predicate<? super String> pred = (Object o) -> o.hashCode() > 0;

Вы также можете видеть, что следующая компиляция проходит:

Predicate<String> preds = s -> s.startsWith("M");
Predicate<Object> predo = (Object o) -> o.hashCode() > 0;
Predicate<? super String> pred = preds;
pred = predo;

т.е. Predicate<? super String> можно назначить как Predicate<String>, так и Predicate<Object>.

При этом обратите внимание, что pred.test() будет принимать только String с, а не любые Object. Причина в том, что переменная pred может ссылаться на Predicate<Object> или Predicate<String> во время выполнения, и только String приемлемо для обоих.

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

Вас, кажется, смущает разница между типом Predicate экземпляра объекта (который создается лямбда-выражением) и типом pred, ссылкой на этот объект.

  • Экземпляр Predicate, созданный лямбдой, имеет тип Predicate<String>.

  • Ссылка pred на объект имеет тип Predicate<? super String> и можетпри этом присваиваются значения как типа Predicate<Object>, так и Predicate<String>.Но метод предиката test можно вызывать только с String объектами!

    Это то, что обеспечивает ограничение ? super String.

Экземпляры объектов всегда имеютпараметры типа какого-то конкретного типа, например Object или String.Только ссылки на могут иметь параметры типа подстановочных знаков.

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