将Collection <someclass>转换为Collection <somesuperclass> </somesuperclass> </someclass>

时间:2010-03-17 09:14:48

标签: java generics casting

我确信之前已经回答了,但我真的找不到它。

我有一个java类SomeClass和一个抽象类SomeSuperClassSomeClass扩展了SomeSuperClass

另一个抽象方法有一个返回Collection<SomeSuperClass>的方法。在实现类中,我有一个Collection<SomeClass> myCollection

我知道我不能只返回myCollection,因为Collection<SomeClass>不会从Collection<SomeSuperClass>继承。不过,我知道myCollection中的所有内容都是SomeSuperClass,因为毕竟它们是SomeClassSomeSuperClass扩展的对象。

我该如何做到这一点?

即。我想要

public class A
{
  private Collection<SomeClass> myCollection;

  public Collection<SomeSuperClass> getCollection()
  {
    return myCollection; //compile error!
  }
}

我发现的唯一方法是通过非泛型类型进行投射并获取未经检查的警告等等。但是必须有更优雅的方式吗?我觉得也不需要使用Collections.checkedSet()和朋友,因为静态地确定返回的集合只包含SomeClass个对象(这不是转发而不是向上转换的情况,但那不是什么我正在做)。我错过了什么?

谢谢!

11 个答案:

答案 0 :(得分:20)

Collection<? extends SomeSuperClass>会不会做你想做的事吗?

答案 1 :(得分:11)

你不能这样做。你有一个集合&lt; SomeClass&gt;并希望返回Collection&lt; SuperClass&gt;

现在想象有人拥有您返回的Collection - 并且他们尝试插入SuperClass,SomeOtherClass的不同的子类。这应该在你的SuperClass系列上允许 - 但它不能,因为它实际上是一个Collection&lt; SomeClass&gt;,除了A的私人成员之外的任何人都不知道。

答案 2 :(得分:5)

Java 8现在使用lambdas提供了一种更简洁的方法:您可以使用map() and collect()函数将对象强制转换为超类。您的示例的解决方案如下所示:

public class A
{
    private Collection<SomeClass> myCollection;

    public Collection<SomeSuperClass> getCollection()
    {
        return myCollection.stream().map(x -> (SomeSuperClass) x).collect(Collectors.toList());
    }
}

如果需要,您还可以使用其他Collectors

答案 3 :(得分:1)

如果您创建了正确类型的新集合,则可以使用旧集合

填充它
public Collection<SomeSuperClass> getCollection()
{
    return new ArrayList<SomeSuperClass>(myCollection); 
}

答案 4 :(得分:1)

基于对此问题的最佳答案: How do you cast a List of supertypes to a List of subtypes?

我相信可以做到

Collection<SomeSuperType> variable =
                    (Collection<SomeSuperType>)(Collection<?>) collectionOfSomeType;

以“未经检查”的警告为代价。在相关问题中,由于缺乏类型安全性,人们对这个答案的“黑客”表示关注。但是,在这个问题的上下文中(即将子类型的集合转换为其超类型的集合),我发现没有问题或可能的ClassCastExceptions。无论如何,它运作良好。

答案 5 :(得分:0)

我不确定为什么;也许别人可以解释一下;但如果你这样做,它会起作用:

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 :(得分:0)

或许,你应该做一些解决方法。

例如,你应该制作一些带有通用扩展名的“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 :(得分:0)

是的,我们可以!

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() ) );

请测试

答案 8 :(得分:0)

这是一个完整的解决方案。

使用以下 static 方法可以避免有关未经检查的强制转换的警告。在返回 result 之前对 result 的看似多余的赋值实际上是必要的,以便能够使用 @SuppressWarnings

/**
 * Casts a {@link Collection} to a {@link Collection} of an ancestral element type.
 *
 * @param collection the {@link Collection} to down-cast.
 * @param <T>        the required ancestral element type.
 *
 * @return the same {@link Collection} where the element type is the given ancestral type.
 */
public static <T> Collection<T> downCast( Collection<? extends T> collection )
{
    @SuppressWarnings( "unchecked" ) Collection<T> result = (Collection<T>)collection;
    return result;
}

如下使用:

class Ancestor {}
class Descendant extends Ancestor {} 
Collection<Descendant> descendants;
Collection<Ancestor> ancestors = downCast( descendants );

也适用于泛型:

class Ancestor<T> {}
class Descendant<T> extends Ancestor<T> {} 
Collection<Descendant<T>> descendants;
Collection<Ancestor<T>> ancestors = downCast( descendants );

答案 9 :(得分:-3)

对于SuperType,SubType的集合不是可替代的

答案 10 :(得分:-3)

.NET 4.0引入了对泛型的协方差和逆变:

http://msdn.microsoft.com/en-us/library/dd799517(VS.100).aspx