2015-01-24 2 views
5

Почему следующий код дает ошибку компиляции?Java Generics - Невозможно преобразовать из <? extends MyObject> to <MyObject>

public MyObject(Builder<? extends MyObject> builder) { 
    // Type mismatch: cannot convert from MyObject.Builder<capture#5-of ? extends MyObject> to MyObject.Builder<MyObject> 
    Builder<MyObject> myObjBuilder = builder; 
} 

Если тип Builder подкласс MyObject, то почему не может назначать строитель просто ввести MyObject? Мне нужно сделать это, потому что я не могу использовать объект типа MyObject с построителем. Посмотрите на этот код, например:

public MyObject(Builder<? extends MyObject> builder) { 
    // The method getData(capture#8-of ? extends MyObject) in the type Builder<capture#8-of ? extends MyObject> is not applicable for the arguments (MyObject) 
    this.data = builder.getData(this); 
} 

Мне кажется, что это должно быть разрешено. Или я чего-то не хватает? Есть ли способ сделать это без литья строителя до (Builder<MyObject>) и использования @SuppressWarnings?

Также обратите внимание, что мне нужно, чтобы Builder был <? extends MyObject>, потому что MyObject и его Builder будут подклассы (как абстрактные).

Благодарим за помощь!

+0

@AlexisKing, я не думаю, что этот вопрос совпадает с этим вопросом, но я думаю, что ему нужен тот же ответ, что и [Что такое риски явного литья из списка типов List в список типов Список в Java?] (http://stackoverflow.com/questions/3403293/what-are-the-risks-of-explicitly-casting-from-a-list-of-type -list-extends-myob) –

+2

См. также [Список Подкласс списка ? Почему не генерические генераторы Java неявно полиморфны?] (Http://stackoverflow.com/q/2745265/465378) –

+0

Я предполагаю, что не использовал правильные ключевые слова для поиска. Я искал какое-то время. спасибо за ссылку – User12345

ответ

4

Потому что Foo<? extends Bar> не является Foo<Bar>.

Say Foo имеет метод:

void add (T t) 

затем по контракту, вы можете только добавить T объекты. Теперь, если T был создан как ? extends Bar, мы не знаем тип. Принятие Bar может привести к проблемному поведению: если у вас есть ArrayList<Foo>, вы ожидаете, что ArrayList будет содержать только Foo экземпляров. Если вы увидите ArrayList<Foo> как ArrayList<SuperFoo>, то нельзя гарантировать, что ArrayList<Foo> содержит только Foo.

Некоторые языки позволяют covariance: если вы используете только T в качестве вывода, можно сказать, что класс Foo<T> является такой же, как Foo<SuperT>, а также (то же самое с входом). Но в настоящее время Java этого не поддерживает. C# однако работает на уровне интерфейса.

+0

Но метод 'add (Object)' фактически * * * принимает любой подкласс 'Object', не так ли? –

+0

@MCEmperor: подкласс да. Но здесь вы хотите «суперкласс» это. Таким образом, вы хотите преобразовать 'ArrayList ' в 'ArrayList '. Это означало бы, что 'add (Integer)' будет принимать 'Object'. По-видимому, это невозможно. –

+0

Я читал о ковариации и неизменности, и теперь все это имеет смысл для меня. Однако в моем случае я знаю, что приведение в Builder типа MyObject будет безопасным во время выполнения, поэтому я думаю, что это будет нормально, даже если это уродливо. Всем спасибо! – User12345

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