Я только что проверил это, само задание компилируется. Что меняется, так это то, можете ли вы на самом деле вызвать predicate.test()
.
Давайте сделаем шаг назад и воспользуемся заполнителем GenericClass<T>
для объяснения. Для аргументов типа Foo
расширяет Bar
, а Bar
расширяет Baz
.
Расширения: когда вы объявляете GenericClass<? extends Bar>
, вы говорите: «Я не знаю, что на самом деле представляет собой его аргумент универсального типа, но это подкласс Bar
». Фактический экземпляр всегда будет иметь аргумент типа, отличного от подстановочного знака, но в этой части кода вы не знаете, каково его значение. Теперь рассмотрим, что это означает для вызовов методов.
Вы знаете, что у вас на самом деле есть либо GenericClass<Foo>
, либо GenericClass<Bar>
. Рассмотрим метод, который возвращает T
. В первом случае возвращаемый тип — Foo
. В последнем Bar
. В любом случае, это подтип Bar
, и его безопасно назначать переменной Bar
.
Рассмотрим метод с параметром T
. Если это GenericClass<Foo>
, то передача ему Bar
является ошибкой — Bar
не является подтипом Foo
.
Таким образом, с верхней границей вы можете использовать общие возвращаемые значения, но не общие параметры метода.
Супер: когда вы объявляете GenericClass<? super Bar>
, вы говорите: «Я не знаю, что на самом деле представляет собой его аргумент универсального типа, но это суперкласс Bar
». Теперь рассмотрим, что это означает для вызовов методов.
Вы знаете, что у вас на самом деле есть либо GenericClass<Bar>
, либо GenericClass<Baz>
. Рассмотрим метод, который возвращает T
. В первом случае возвращается Bar
. В последнем Baz
. Если он возвращает Baz
, то присвоение этого значения переменной Bar
является ошибкой. Вы не знаете, что это такое, поэтому вы не можете с уверенностью предполагать что-либо здесь.
Рассмотрим метод с параметром T
. Если это GenericClass<Bar>
, то передача Bar
допустима. Если это GenericClass<Baz>
, то передача ему Bar
по-прежнему допустима, потому что Bar
является подтипом Baz
.
Таким образом, с нижней границей вы можете использовать общие параметры метода, но не общие возвращаемые значения.
В итоге: <? extends T>
означает, что вы можете использовать общие возвращаемые значения, но не параметры. <? super T>
означает, что вы можете использовать общие параметры, но не возвращать значения. Predicate.test()
имеет общий параметр, поэтому вам нужен super
.
Еще одна вещь, которую следует учитывать: границы, указанные подстановочным знаком, относятся к фактическому аргументу типа объекта. Их последствия для типов, которые вы можете использовать с этим объектом, противоположны. Подстановочный знак верхней границы (extends
) — это нижняя граница типов переменных, которым можно присваивать возвращаемые значения. Подстановочный знак нижней границы (super
) — это верхняя граница типов, которые вы можете передавать в качестве параметров. predicate.test(new Object())
не будет компилироваться, потому что с нижней границей String
он будет принимать только подклассы String
.
person
Douglas
schedule
10.02.2016
extends
тоже компилируется --Predicate<? extends String> predicate = s -> s.startsWith("g")
-- однако мы не можем передатьString
этому предикату:) см. также мою статью по подстановочному знаку - person ZhongYu   schedule 10.02.2016Predicate<? super String>
не означает, что вы можете передать емуObject
(и попытка сделать это вызовет ошибку компилятора). ПодписьPredicate<? super String>
просто подразумевает, что может бытьPredicate<Object>
, что нормально, поскольку этот предикат по-прежнему способен обрабатыватьString
входных данных. Другими словами,Predicate<? super String>
говорит, что этот предикат может потреблять строки независимо от его фактического типа, поэтомуPredicate<String>
является действительной реализациейPredicate<? super String>
. - person Holger   schedule 10.02.2016