Литье Коллекция <SomeClass> в коллекцию <SomeSuperClass>
Я уверен, что на это уже был дан ответ, но я действительно не могу его найти.
У меня есть класс java SomeClass
и абстрактный класс SomeSuperClass
. SomeClass
extends SomeSuperClass
.
Другой абстрактный метод имеет метод, который возвращает Collection<SomeSuperClass>
. В классе реализации у меня есть Collection<SomeClass> myCollection
Я понимаю, что я не могу просто вернуть myCollection
, потому что Collection<SomeClass>
не наследует от Collection<SomeSuperClass>
. Тем не менее, я знаю, что все в myCollection
является SomeSuperClass
, потому что в конце концов это объекты SomeClass
, которые расширяют SomeSuperClass
.
Как я могу сделать эту работу?
т.е. Я хочу
public class A
{
private Collection<SomeClass> myCollection;
public Collection<SomeSuperClass> getCollection()
{
return myCollection; //compile error!
}
}
Единственный способ, которым я нашел, - это кастинг через не-общий тип и получение непроверенных предупреждений и еще много чего. Однако должен быть более элегантный способ? Я чувствую, что также использование Collections.checkedSet()
и друзей не нужны, поскольку статически очевидно, что возвращенная коллекция содержит только объекты SomeClass
(это не будет иметь место, если downcasting вместо повышения, но это не то, что я делаю). Что мне не хватает?
Спасибо!
Ответы
Ответ 1
Вы не можете этого сделать. У вас есть Collection <SomeClass> и хотите вернуть Collection <SuperClass>
Теперь представьте, что у кого-то есть ваша возвращенная коллекция - и они пытаются вставить другой подкласс SuperClass, SomeOtherClass. Это должно быть разрешено в вашей коллекции SuperClass, но это невозможно, потому что на самом деле это Collection <SomeClass> , без ведома для кого-либо, кроме частного члена A.
Ответ 2
Будет ли Collection<? extends SomeSuperClass>
делать то, что вам нужно?
Ответ 3
Java 8 теперь предлагает более аккуратный способ сделать это, используя lambdas: вы можете использовать функции map() и collect() для приведения объектов в свой суперкласс. Решение для вашего примера будет выглядеть так:
public class A
{
private Collection<SomeClass> myCollection;
public Collection<SomeSuperClass> getCollection()
{
return myCollection.stream().map(x -> (SomeSuperClass) x).collect(Collectors.toList());
}
}
Вы также можете использовать другие Collectors, если это необходимо.
Ответ 4
Если вы создаете новую коллекцию нужного типа, ее можно заполнить с помощью старой коллекции
public Collection<SomeSuperClass> getCollection()
{
return new ArrayList<SomeSuperClass>(myCollection);
}
Ответ 5
Я не уверен, почему; возможно, кто-то еще может это объяснить; но он работает, если вы выполните:
public abstract class SomeSuperClass<E> {
abstract public Collection<SomeSuperClass<E>> getCollection();
}
и
public class Someclass extends SomeSuperClass {
@Override
public Collection<Someclass> getCollection() {
// TODO Auto-generated method stub
return null;
}
}
Ответ 6
возможно, вы должны сделать некоторое обходное решение.
например, вы должны сделать несколько "HolderClass" с общим расширением, а затем вы сможете поместить свой SomeClass, выбери свой SomeSuperClass.
взгляните:
public class HolderClass<E extends SomeSuperClass> {
private final Collection<E> myClass;
public HolderClass() {
myClass = new ArrayList<E>();
}
public void putSomeClass(final E clazz) {
myClass.add(clazz);
}
public Collection<E> getMyClasses() {
return myClass;
}
}
и вы можете сделать сборку таким образом:
HolderClass<SomeSuperClass> holderClass = new HolderClass<SomeSuperClass>();
holderClass.putSomeClass(new SomeClass());
holderClass.putSomeClass(new SomeSuperClass());
и теперь, когда вы вызываете getMyClasses(), вы получите коллекцию SomeSuperClasses
Ответ 7
Основываясь на главном ответе на этот вопрос:
Как вы делаете список супертипов в список подтипов?
Я действительно считаю, что можно сделать
Collection<SomeSuperType> variable =
(Collection<SomeSuperType>)(Collection<?>) collectionOfSomeType;
За счет "непроверенного" предупреждения. По связанному вопросу была высказана озабоченность по поводу "халатности" этого ответа из-за отсутствия безопасности типа. Однако в этом вопросе (а именно, литье коллекции подтипов в коллекцию их супертипов) я не вижу никаких проблем или возможных ClassCastExceptions. И в любом случае, он работает достаточно хорошо.
Ответ 8
Да, мы можем!
class A {@Override
public String toString()
{
return "A";
} };
class B extends A {
@Override
public String toString()
{
return "B";
}
};
List<A> l1 = new ArrayList<A>();
l1.add(new A());
List<B> l2 = null;
l2 = (List<B>)(List<? extends A>)l1;
l2.add(new B());
System.out.println( Arrays.toString( l2.toArray() ) );
пожалуйста, протестируйте его
Ответ 9
Коллекция SubType не подставляется для SuperType.
Ответ 10
.NET 4.0 вводит ковариацию и контравариантность к дженерикам:
http://msdn.microsoft.com/en-us/library/dd799517(VS.100).aspx