2010-03-17 41 views
21

我确信这已被回答之前,但我真的找不到它。铸造收集<SomeClass>收集<SomeSuperClass>

我有一个java类SomeClass和一个抽象类SomeSuperClassSomeClass延伸SomeSuperClass

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

我明白,我不能只返回myCollection,因为Collection<SomeClass>没有从Collection<SomeSuperClass>继承。尽管如此,我知道myCollection中的所有内容都是SomeSuperClass,因为毕竟它们是SomeClass对象,它们扩展了SomeSuperClass

我该如何做这项工作?

I.e.我想要

public class A 
{ 
    private Collection<SomeClass> myCollection; 

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

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

谢谢!

回答

11

你不能这样做。有一个集合< SomeClass的>并希望返回一个集合<父类>

现在,假设某人有你的返回集合 - 他们试图插入不同子类父类,SomeOtherClass的。这应该让你的父类集合 - 但它不能因为它实际上是一个集合< SomeClass的>,不知情的人,但A.

+0

啊哈!谢谢:-) 听起来像我需要一个不可变的视图。 – skrebbel 2010-03-17 09:23:14

+0

嗯,标准库支持不可变视图吗? :-) – skrebbel 2010-03-17 09:26:45

+0

为什么'我的解决方案'可能?我错过了什么(请看下面的答案) – 2010-03-17 09:39:32

-3

的私有成员子类型的集合是不是超替代

+0

那么,很明显,我知道这一点。我的问题是我想解决这个问题。我真正的问题是,我不明白*为什么* SubType的集合不能替代SuperType。通过“你不能做X”来回答“我不能做X,是否有解决方法”的问题,听起来就像你只是想获得stackoverflow点。 – skrebbel 2010-03-17 09:46:47

+1

错过了“更优雅的方式”中间的位。我站在纠正... – Everyone 2010-03-17 09:59:12

+0

你可能想要在http://stackoverflow.com/questions/15496/hidden-features-of-java/55221#55221 – Everyone 2010-03-17 10:14:59

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; 
    } 
} 
+0

gander我也很感兴趣。确定你没有得到任何未经检查的警告?无论哪种方式,你扩展一个泛型类,而不使子类通用,这听起来像一个奇怪的事情开始... – skrebbel 2010-03-17 09:48:46

+0

是的,这很奇怪。如果你这样做使子类更具体的你: 公共类SomeClass的扩展SomeSuperClass { \t @覆盖 \t公文集> getCollection(){ \t \t // TODO自动生成方法存根 \t \t返回null; \t} } 我以前从来没有使用过这样的结构,它对我来说看起来并不是一个好方法。 – 2010-03-17 11:41:51

+0

您的Someclass扩展了SomeSuperClass,它是一个原始类型,因为SomeSuperClass被声明为。我相信,由于您扩展了原始类型,因此您将得到一个警告,但是即使它们实际上未经过检查的转换,也不会对各个方法进一步发出未经检查的警告。 – 2010-03-17 18:12:59

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

的集合
20

请问Collection<? extends SomeSuperClass>不是你想要的吗?

+3

这是解决这个问题的正确方法。请参阅:http://java.sun.com/docs/books/tutorial/extra/generics/wildcards.html – Adam 2010-07-01 15:21:40

+0

请注意,在API中使用时:“不要使用通配符类型作为返回类型,而不是为您的应用程序提供额外的灵活性用户,它会强制他们在客户端代码中使用通配符类型。“有效的Java项目28 https://stackoverflow.com/a/22815270/774398 – for3st 2017-05-26 11:46:29

1

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

public Collection<SomeSuperClass> getCollection() 
{ 
    return new ArrayList<SomeSuperClass>(myCollection); 
} 
0

基于对此问题最多的回答来填充它: How do you cast a List of supertypes to a List of subtypes?

我相信它是可能做

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

以“unchecked”警告为代价。在相关问题上,由于缺乏类型安全性,对此答案的“冒险”表示担忧。但是,在这个问题的上下文中(即将一个子类型集合转换为它们的超类型集合),我没有看到任何问题或可能的ClassCastExceptions。无论如何,它工作得很好。

5

Java 8现在使用lambdas提供了一个更好的方法:您可以使用map() and collect()函数将对象转换为您的超类。 a。对于示例解决方案是这样的:

public class A 
{ 
    private Collection<SomeClass> myCollection; 

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

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

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

请测试它