Подтвердить что ты не робот

Литье Коллекция <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 вместо повышения, но это не то, что я делаю). Что мне не хватает?

Спасибо!

4b9b3361

Ответ 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.