2013-08-16 2 views
4

У меня есть следующие классы:классы Java Generic Переуступка

public interface ModelObject { 
    } 
    public interface Resource { 
    } 
    public interface Transformer <F,T>{ 
    } 
    public interface WrapperFactory { 
     Transformer<Resource, Wrap<? extends ModelObject>> createMapper(); 
    } 
    public class Wrap<E extends ModelObject> { 

    } 

    public class AbstractBaseTransformer<F,T> implements Transformer<F,T> { 
    } 
    public class ConcreteModel implements ModelObject { 

    } 
    public class ConcreteTransformer extends AbstractBaseTransformer<Resource, Wrap<ConcreteModel>> { 

    } 
    public class ConcreteFactory implements WrapperFactory { 

     @Override 
     public Transformer<Resource, Wrap<? extends ModelObject>> createMapper() { 
      return new ConcreteTransformer(); 
     } 
    } 

ConcreteFactory не компилирует о том, что ConcreteTransformer несовместима с возвращено

Transformer<Resource, Wrap<? extends ModelObject>> 

Я не могу увидеть, что здесь не так. ConcreteTransformer связывает 1-й параметр ресурса (так же, как и ожидалось) при связывании 2-й параметр для:

Wrap<ConcreteModel> 

, который должен связываться с:

Wrap<? extends ModelObject> 

в ConcreteModel реализует его.

+0

Является ли это происходит в Eclipse, или в JDK? Компилятор Eclipse содержит несколько ошибок. – gparyani

+2

@dsmog Правильная терминология - это «generics» (Java), «классы шаблонов» (синтаксически подобная, но концептуально очень различная концепция в C++). –

ответ

4

Вот более простой вариант, чтобы сузить вопрос:

interface ModelObject {} 
class ConcreteModel implements ModelObject {} 

class Wrap<E extends ModelObject> {} 
class SomeGeneric<T> {} 

class Simple { 
    public SomeGeneric<Wrap<? extends ModelObject>> m() { 
     return new SomeGeneric<Wrap<ConcreteModel>>(); 
    } 
} 

не компилируется либо.

Ваша проблема в том, что SomeGeneric<Wrap<ConcreteModel>> is not a SomeGeneric<Wrap<? extends ModelObject>>.

+0

+1 для анестезии – Bohemian

0

A Wrap<ConcreteModel> может быть присвоен переменной типа Wrap<? extends ModelObject>. Но дело здесь сложнее.

Предположим, у вас есть ArrayList<Wrap<? extends ModelObject>> list. Если у вас такой тип, это означает, что вы можете добавить в список Wrap<ConcreteModel>, но это также означает, что вы можете добавить к нему Wrap<ModelObject>. Короче говоря, это означает, что у вас есть список, который может содержать обертывание всего, что можно отличить от ModelObject.

С другой стороны, имея ArrayList<Wrap<ConcreteModel>> list означает, что вы можете только добавить Wrap<ConcreteModel> S к нему, в то время как Wrap<ModelObject> не могут быть добавлены к нему, потому что список может содержать только завернутые ConcreteModel с, и завернуты ModelObject не обернуты ConcreteModel и он не может быть отлит одним.

Это именно ваш случай. Вы указали свой метод createMapper(), чтобы вернуть Transformer<Resource, Wrap<? extends ModelObject>>. Это означает, что второй аргумент возвращаемого трансформатора должен быть любым подклассом ModelObject, включая сам ModelObject. Напротив, вы пытаетесь вернуть Transformer<Resource, Wrap<ConcreteModel>>.

Компилятор должен применять это потому, что Transformer<F, T> может объявить метод:

void myMethod(F fObject, T tObject); 

Если это так, метод myMethod объекта типа Transformer<Resource, Wrap<? extends ModelObject>> будет принимать объект типа ModelObject в качестве второго аргумента , С другой стороны, тот же метод, в объекте типа Transformer<Resource, Wrap<ConcreteModel>>не может принять второй аргумент ModelObject.

1

Wrap<ConcreteModel> - это подтип Wrap<? extends ModelObject>? Да.

Transformer<Resource, Wrap<ConcreteModel>> - это подтип Transformer<Resource, Wrap<? extends ModelObject>>? Нет.

Это то же самое, как:

String является подтипом Object? Да.

List<String> является подтипом List<Object>? №

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

То, что вы, вероятно, хотел вместо этого

Transformer<Resource, ? extends Wrap<? extends ModelObject>>

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