2011-12-30 8 views
2

Я изучаю SCJP/OCPJP, и я наткнулся на образец вопроса, который кажется странным для меня.Создание родоначальника класса <?>

Пример кода экземпляра две родовые коллекции:

List<?> list = new ArrayList<?>(); 
List<? extends Object> list2 = new ArrayList<? extends Object>(); 

«Правильный» ответ на вопрос, что этот код компилируется, но при добавлении в любой коллекции будет производить ошибки во время выполнения.

Когда я пытаюсь скомпилировать такой код, я просто получаю ошибки. Учебник Java не показывает этот тип кода, вместо этого он обычно использует подстановочные знаки в качестве части ускорения.

Collection<?> c = new ArrayList<String>(); 

Являются ли две общие коллекции выше даже законного кода? Вторая по моей логике будет только запрещать интерфейсы. Первый выглядит совершенно бесполезным. Зачем использовать общий элемент, который не пытается контролировать?

+0

Не видите, как это будет скомпилировано И вы можете добавить в обе коллекции просто отлично - только точно один объект. Я оставляю это как упражнение для читателя, чтобы выяснить, какой объект действителен для каждого класса :) – Voo

+0

Вы тоже не можете. Я хотел узнать, был ли образец вопрос/ответ неправильным и, по-видимому, это так. – jeremyjjbrown

+0

Вниз проголосовали именно по какой причине? – jeremyjjbrown

ответ

4

Заканчивать отличный Java generics tutorial PDF. Более конкретно раздел о подстановочных символах содержит ответ на ваш вопрос, и я цитирую

Collection<?> c = new ArrayList<String>(); 
c.add(new Object()); 

Поскольку мы не знаем, что тип элемента c стендов для, мы не может добавлять объектов к нему. Метод add() принимает аргументы типа E, тип элемента типа . Когда фактическим параметром типа является ?, это означает какой-то неизвестный тип. Любой параметр, который мы передаем для добавления, должен быть должен быть подтипом этого неизвестного типа. Поскольку мы не знаем, что такое , то мы не можем передать ничего. Единственным исключением является null, , который является членом любого типа.

+0

Этот документ очень полезен. Спасибо! Знаете ли вы о каких-либо статьях, которые хороши для размышлений или внутренних занятий? – jeremyjjbrown

1

Я ответил на это несколько раньше в this ответ. ? не могут быть использованы в создании. Я не уверен, почему он говорит, что код будет компилироваться, ни один из компиляторов java, которые я использовал, не допустил бы этого. Вы могли бы сделать то, что показано выше, следующим образом:

List<?> list = new ArrayList(); 

Это было бы скомпилировать и запустить, но вы не можете сделать:

list.add("hello world"); //This wouldn't compile 
2

Если вы хотите объявить тип во время выполнения, вы можете сделать что-то вроде этого:

public class Clazz1<T> { 

private final List<T> list = new ArrayList<T>(); 

private List<T> getList() { 
    return list; 
} 

/** 
* @param args 
*/ 
public static void main(String[] args) { 
    Clazz1<Integer> clazzInt = new Clazz1<Integer>(); 
    clazzInt.getList().add(2); 
    System.out.println(clazzInt.getList()); 

    Clazz1<String> clazzString = new Clazz1<String>(); 
    clazzString.getList().add("test"); 
    System.out.println(clazzString.getList()); 
} 

} 
0

new производит конкретный экземпляр объекта. Конкретный экземпляр может иметь только один тип, включая любые дженерики. Зная это, подстановочные знаки не могут работать с new.