2014-07-08 3 views
2

я прочитал следующие две ссылки для ява дженериков подстановочные знакиJava подстановочные путая пример

Difference between generic type and wildcard type

и

Are wildcard generics really needed?

Я до сих пор не понимаю, символы того, как это компилирует,

public void foo(List<List<?>> t) { 
    t.add(new ArrayList<String>()); 
    t.add(new ArrayList<Integer>()); 
} 

, но это не делает,

public static void funct2(final List<?> list, final Object something) { 
     list.add(something); // does not compile 
    } 

Разве мы не делаем то же самое во втором блоке кода, как первый?

ответ

2

Первый пример метод имеет параметр List<List<?>>. Параметр типового типа - List<?>, а это означает «любой List любого типа», поэтому он принимает ArrayList<String> и ArrayList<Integer>. После стирания типа JVM все равно видит List и ArrayList. Обратите внимание, что только List<?> может возникнуть из t, независимо от того, что вошло. Но ArrayList<String> - это List<?>, а ArrayList<Integer> - также List<?>.

Второй примерный метод имеет параметр List<?>. Параметр generic type - это простой подстановочный знак - конкретный, но неизвестный тип. Это может быть List<String>, a List<Object> или List<Foo>; компилятор не знает. Компилятор должен запретить вызов метода add с чем угодно, кроме null, поскольку он не может гарантировать безопасность типа. Объект something, добавляемый в список, может быть Integer, а list может быть List<Foo> для всего, что он знает.

Разница заключается в том, что в первом примере, оба объекта добавляются являются List с, пока во втором примере, простой Object в настоящее время передается в List, который содержит неизвестный тип. Первое разрешено, а второе не разрешено, как я объяснил выше.

Семантика List<List<?>> - это «список списков любого типа», но семантика List<?> - это «список определенного неизвестного типа».

0

Во втором примере вы можете получить только из списка, вы не сообщаете компилятору, какие объекты получают этот список something не будут приняты в List<?> list.

Вам нужно изменить что-то вроде:

public static <E> void funct2(final List<E> list, final E something) { 
    list.add(something); 
} 
1

Это странно, и нелепо. Я постараюсь объяснить все, что могу. В первом примере список, который вы добавляете, соответствует шаблону шаблона. Другими словами, List<List<?>> - это список, который может содержать любой тип параметризованного списка, и это то, что вы добавляете.

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

Во втором примере List<?> - это список, который может содержать любой объект, но мы не знаем, что это за тип этого объекта. Поскольку мы не знаем, вы не можете добавить какой-либо тип вообще безопасно. Если список был List<Integer>, а something был String, хорошо, что не соответствует, поэтому не-go.

Это странно, потому что это не кажется последовательным. Иногда вы можете добавлять вещи, а иногда и не можете. Но вы должны рассуждать о том, что запрашивается, и почему. В крайнем случае компилятор скажет вам. Попытайтесь работать в обратном направлении от того, что говорит компилятор, это поможет вам понять, что вы делаете неправильно (или правильно).

1

конструктов

List<?> 

и

List<List<?>> 

в то время как внешне очень похожи, на самом деле имеют принципиально разные семантики.

Смысл первой конструкции с не-вложенным шаблоном - это «List, параметризованный определенным определением, но в этом контексте неизвестный тип».

Смысл второй конструкции, с вложенным символом, является «List из любого вида List с».

Вот почему вы можете, например, объявить

class ListOfLists implements List<List<?>> {...} 

но не

class ListOfSomething implements List<?> {...} 

Кроме того, это законно:

List<?> xs = new ArrayList<Integer>(); 

, но не это:

List<List<?>> lists = new ArrayList<List<Integer>>(); 

Основываясь на том, что должно быть ясно, что вы можете добавить любой вид списка на List<List<?>>, но не может добавить Object к List<?>, потому что это действительно может быть List<String> или любого другого типа, а также добавление Object будет явно незаконным.

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