2012-01-16 4 views
4

Можно создать дубликат:
Why won't this generic java code compile?Почему это (неправильное) использование Java-дженериков не компилируется?

Учитывая следующий код:

import java.util.Collections; 
import java.util.List; 

public class ComeGetSome { 
    //TODO: private final Some<?> some = new Some(); 
    private final Some some = new Some(); 

    public static void main(String[] args) { 
    new ComeGetSome().dude(); 
    } 

    public void dude() { 
    for (String str : some.getSomeStrings()) { //FIXME: does not compile! 
     System.out.println(str); 
    } 
    } 
} 

class Some<T> { 
    public List<String> getSomeStrings() { 
    return Collections.<String> emptyList(); 
    } 
} 

Это не компилируется, потому что some.getSomeStrings() возвращает необработанный List. Но подпись метода указывает, что она возвращает List<String>!

Как-то это связано с тем фактом, что Some имеет объявление типа, но имеет ссылку как необработанный тип. Исправлена ​​проблема с ссылкой на Some<?>. Но метод не имеет ничего общего с объявлением типа в классе!

Почему компилятор ведет себя так?

+0

Collections.emptyList () ?? –

+0

См. Также http://stackoverflow.com/questions/1661068/java-generics-vanishing-type-information –

ответ

4

Если вы используете сырой (нетипизированный) экземпляр универсального класса, то он рассматривается как полностью сырье, то есть вся общий вид информация игнорируется, даже если тип игнорируется является не связан с общий тип, который был опущен.

Вот почему это ...

private final Some<?> some = new Some(); 

... фиксирует ошибку - он использует напечатал версию Some (хотя и одного шаблона)

1

Ну, прежде всего, это не имеет смысла объявлять класс Some generic, если вы фактически не используете параметр определенного типа. И это на самом деле источник проблем. Вы экземпляр член поля этого типа в этом фьюжн:

private final Some some = new Some(); 

Это заявление о сырого типа - это общий тип с параметрами его типа опущены. Это фактически означает не только то, что его собственный параметр типа T выброшен, но и все из общих типов, используемых в методах этого класса, игнорируются, включая параметр <String> в public List<String> getSomeStrings().

Так что решение на самом деле просто, цитируя Джошуа Блох:

Не используйте сырые типы в новом коде.

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

private final Some<?> some = new Some(); 

исправляет проблему, но на самом деле генерирует предупреждение компилятора (незарегистрированный операция).чистый путь будет либо объявить фактический параметр типа на правой стороне заявления, такие как:

private final Some<String> some = new Some<String>(); 

типа вы положили в общий параметр может любого типа вы хотите, это зависит от того, в котором вы намерены использовать класс Some. Но если вы на самом деле не нужен параметр типа, просто удалите его и код будет работать нормально:

class Some { ... } 

Примечание стороны: это не нужно явно объявить параметр String в этом коде:

return Collections.<String> emptyList(); 

компилятор выводит общий тип из сигнатуры метода, так что вы можете упростить код для этого:

public List<String> getSomeStrings() { 
    return Collections.emptyList(); 
    } 

Edit: Говоря Джошуа Блох, есть хороший Java головоломка относительно этого фактического вопроса в своем выступлении на конференции Google I/O 2011 в: http://www.youtube.com/watch?v=wbp-3BJWsU8&t=36m04s

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