2014-01-22 2 views
0

У меня ошибка компилятора «несовместимых типов» в состоянии, которое еще не обсуждалось в stackoverflow (например, Why won't this generic java code compile?).Java generics & несовместимые типы: ошибка в компиляторе?

Мое ожидание простое - я вызываю шаблонный метод, который не использует какие-либо «общие» классы из класса, поэтому он должен извлекать типы параметров шаблона из аргументов метода, и это должно компилироваться во всех случаях - но я получить ошибку компилятора «несовместимые типы».

Я заметил странный способ исправить проблему - добавление «<? Extends Data>» в общий тип данных в аргументах метода. Как это изменяет логику компилятора?

В моем понимании - не должно быть никакой разницы, потому что параметры шаблона (1) DataContainer класса не используется в вызове метода и (2) ограничение „< TDATA расширяет данные>“ уже определяет минимальный базовый класс объекта - Data - и поэтому его следует автоматически принимать при компиляции шаблона без аргументов.

public void processData(DataContainer<? extends Data> c) { 

(явное приведение типа может быть использован, но я считаю, что это избыточно здесь)

DummyContextClass dcc = (DummyContextClass)c.getContext(DummyContextClass.class); 

код для копирования/вставки

public class Test { 

    public static class Data { 
    } 

    public static class DataContainer<TData extends Data> { 
     public final TData Data; 
     private final Map<String, Object> contexts = new HashMap<>(); 

     public DataContainer(TData data) { 
      Data = data; 
     } 

     public <T> T getContext(Class<T> type) { 
      return (T)contexts.get(type.getName()); 
     } 

     public <T> void setContext(Class<T> type, T context) { 
      contexts.put(type.getName(), context); 
     } 
    } 

    public static class DummyContextClass { 
    } 

    public void processData(DataContainer c) { 
     c.setContext(DummyContextClass.class, new DummyContextClass()); 

     // error: incompatible types: Object cannot be converted to DummyContextClass 
     DummyContextClass dcc = c.getContext(DummyContextClass.class); 
    } 
} 

ответ

6

Проблема не имеет ничего (много), чтобы делать с вашими общими методами.
Вашей проблема заключается в использовании сырого типа в качестве параметра вашего метода:

public void processData(DataContainer c) { // Oops! DataContainer is a raw type 

Вы должны использовать параметр с DataContainer:

public void processData(DataContainer<? extends Data> c) { 

Когда вы покидаете от Типа generic class, у вас есть так называемый тип raw и (из-за требований совместимости со старыми версиями java), вся общая информация удаляется из класса. Это (помимо всего прочего) меняет все возвращаемые типы, которые заявлены в качестве родовых типов в Object, поэтому для целей компиляции, ваш метод теперь выглядит следующим образом:

public Object getContext(Class type) { 

... поэтому ваша ошибка.

+1

Вы можете удалить 'extends Data', поскольку он является избыточным. – Njol

+0

Это кажется бессмысленным, поскольку кто-то может создать не-общий класс, который имеет общие методы, и это будет работать нормально. 'T' не имеет никакого отношения к' TData', поэтому нет никакой причины, чтобы эта общая информация была удалена. Это так же глупо, как переменные аргументы, обрабатывающие неквалифицированный «null» как нулевой массив вместо «new DataType [] {null}» только потому, что люди использовали явные массивы перед переменными аргументами. – JAB

+0

@ user902383 Это не должно иметь никакого отношения к этому, параметр 'T' полностью не связан с' TData'. – JAB

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