2017-02-05 7 views
3

Я понимаю, что одна из причин, по которой существуют ограниченные подстановочные знаки, заключается в том, что коллекция не является неизменной при добавлении новых элементов.Ограниченные ограничения Java - доступ к методам

E.g.

List<? extends Number> obj = new ArrayList<>();//Now this list is immutable 
obj.add(new Integer(5));//Does not compile 
List<? super Number> objTwo = new ArrayList<>();//This list is mutable 
objTwo.add(new Integer(5));//Compiles 

Следующие не скомпилируются, потому что я пытался получить длинное значение чисел.

Q1: Какие методы я мог бы использовать? Только Объекты методы ?:

public void testLowerBounds(List<? super Number> numbers){ 
     if (!numbers.isEmpty()){ 
      System.out.println(numbers.get(0).longValue());//Does not compile 
     }  

}

Как мой вопрос возник: я в настоящее время изучение потоков и книга определяет следующий метод потока:

Optional<T> min(Comparator<? super T> comparator) 

и инвентарь это следующим образом:

Stream<String> s = Stream.of("monkey", "ape", "bonobo");  
Optional<String> min = s.min((s1, s2) -> s1.length()—s2.length()); 

Q2: Как компаратору разрешено использовать строковые методы при использовании?

Если бы мне пришлось ответить Q2: я бы сказал, что опционально указывает: «Вы должны передать мне реализацию Компаратора, который имеет общий тип« String »или что-то, что реализует« String ». Я был бы прав в том, чтобы сказать это?

с нетерпением жду вашего ответа.

+0

Это, по-видимому, два разных вопроса. И что касается первого предположения, когда компилятор предотвращает добавление в список, это означает, что список не является неизменным. Компилятор просто подчиняется правилам проверки статического типа языка. – manouti

+0

Также 'List' не имеет метода' longValue() '. – manouti

+0

Привет, AR.3 спасибо за отзыв. Я изменил вопрос, поскольку вы были правы, я проверял метод списка, а не содержимое. У них действительно два разных вопроса, я просто хотел объяснить происхождение вопроса. Я получаю то, что вы говорите о неизменяемости, но теперь он логически неизменен, поскольку компилятор не позволит вам добавить в список. У вас есть ответы на любой вопрос сейчас? –

ответ

1

Прежде всего, не следует путать параметры типа подстановочные с изменчивостью. Имея маски в List «s типа элемента делает не предотвратить изменения, это только накладывает несколько практических ограничений на то, что вы можете сделать с помощью lis т.

Наличие списка, указанного как List<? extends Number>, подразумевает, что ссылочный список имеет фактический тип элемента Number или подкласс Number, например. это может быть List<Integer> или List<Double>. Таким образом, вы не можете добавить произвольный экземпляр Number, так как вы не можете знать, совместим ли он с фактическим типом элемента.

Но вы все равно можете добавить null, так как ссылка null, как известно, совместима со всеми ссылочными типами. Кроме того, вы всегда можете удалить элементы из списка, например. звоните remove или clear без проблем. Вы также можете вызвать методы, подобные Collections.swap(list, index1, index2), что интересно, поскольку было бы нецелесообразно вызывать list.set(index1, list.get(index2)) из-за формальных правил, относящихся к типам подстановочных знаков, но передавая список другому методу, который может использовать переменную типа без подстановочных знаков для представления элемента списка типа. Это, безусловно, правильно, поскольку он устанавливает только элементы, происходящие из одного и того же списка, которые должны быть совместимы.

Аналогичным образом, если у вас есть Comparator<Number>, вы можете позвонить Collections.sort(list, comparator), поскольку компаратор, который может обрабатывать произвольные номера, сможет обрабатывать любые числа, которые фактически хранятся в списке.

Подводя итог, наличие ? extends в типе элементов коллекции не предотвращает модификации.


Как уже говорилось, вы не можете вставить произвольные новые элементы в список, чей фактический элемент типа может быть неизвестный подкласс связанный, как с List<? extends Number>. Но при получении элемента вы получите экземпляр Number, так как каждый экземпляр подтипа Number также является экземпляром Number. Когда вы объявляете List<? super Number>, его фактический тип элемента может быть Number или супер тип Number, например. Object или Serializable. Вы можете вставить произвольные Number экземпляры, так как вы знаете, что он будет совместим с любым типом фактического элемента, который имеет список, поскольку он является супертипом числа. Когда вы извлекаете экземпляр, вы знаете только, что это экземпляр Object, так как это супер тип всех экземпляров. Для сравнения с футляром ? extends, объявление ? super не препятствует чтению, оно лишь накладывает некоторые практические ограничения. Точно так же вы можете передать его Collections.swap, потому что, независимо от того, насколько мало мы знаем о фактическом типе, работает то, что мы только что извлекли из того же списка.

В вашем втором вопросе вы сбиваете с толку стороны. Вы теперь не смотрите на реализацию min, но на вызывающий абонент. Объявление min(Comparator<? super T> c) позволяет вызывающему лицу передавать любой компаратор с параметрами T или супер-тип T. Поэтому, когда у вас есть Stream<String>, это действительно так, чтобы передать Comparator<String> методу min, который является именно тем, что вы используете с помощью выражения лямбда (s1, s2) -> s1.length()—s2.length() (хотя я бы предпочел Comparator.comparingInt(String::length)).

В рамках реализации min, действительно нет знаний о том, что либо T, либо фактический аргумент типа Comparator, есть. Но достаточно знать, что любой элемент потока, который имеет тип T, может быть передан методу compare компаратора, который может ожидать T или супер тип T.

+0

Спасибо @Holger. У вас были хорошие объяснения. Мне особенно понравился ответ на мой второй вопрос (Ницца лямбда, кстати, используя ссылки на методы). Я понимаю вашу изменчивость. С ответом на мой первый вопрос, который я собрал, вы говорите, что я имею доступ только к методам Object, и это то, что я ожидал, поскольку ссылочным типом может быть объект, так как это информация, которую вы имеете в данный момент. –

Смежные вопросы