【问题标题】:casting Collection<SomeClass> to Collection<SomeSuperClass>将 Collection<SomeClass> 转换为 Collection<SomeSuperClass>
【发布时间】:2010-03-17 09:14:47
【问题描述】:

我确定这个问题之前已经回答过了,但我真的找不到。

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

另一个抽象方法有一个返回Collection&lt;SomeSuperClass&gt; 的方法。在一个实现类中,我有一个Collection&lt;SomeClass&gt; myCollection

我知道我不能只返回myCollection,因为Collection&lt;SomeClass&gt; 不继承自Collection&lt;SomeSuperClass&gt;。尽管如此,我知道myCollection 中的所有内容都是SomeSuperClass,因为毕竟它们是扩展SomeSuperClassSomeClass 对象。

我怎样才能做到这一点?

即我想要

public class A
{
  private Collection<SomeClass> myCollection;

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

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

谢谢!

【问题讨论】:

    标签: java generics casting


    【解决方案1】:

    Collection&lt;? extends SomeSuperClass&gt; 会不会做你想做的事?

    【讨论】:

    【解决方案2】:

    你不能这样做。您有一个 Collection 并希望返回一个 Collection

    现在假设有人拥有您返回的集合 - 他们尝试插入 SuperClass 的 不同 子类 SomeOtherClass。这应该在您的 SuperClass 集合上允许 - 但它不能,因为它实际上是一个 Collection,除了 A 的私有成员之外,任何人都不知道。

    【讨论】:

    • 啊哈!谢谢 :-) 听起来我需要一个不可变的视图。
    • 嗯,不可变视图有标准库支持吗? :-)
    • 为什么“我的解决方案”可能?我错过了什么吗(请参阅下面的答案)
    • -1 你可以这样做。请参阅下面使用通配符的 ishmeister 的回答。
    • Java 支持Collections 中的不可修改视图。 unmodifiable 方法也接受类型参数并允许它返回超类类型的集合。 public static &lt;T&gt; Collection&lt;T&gt; unmodifiableCollection(Collection&lt;? extends T&gt; c)
    【解决方案3】:

    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

    【讨论】:

      【解决方案4】:

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

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

      【讨论】:

        【解决方案5】:

        根据对该问题的最高回答: How do you cast a List of supertypes to a List of subtypes?

        我相信这是可能的

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

        以“未经检查”的警告为代价。在链接的问题上,由于缺乏类型安全性,人们对此答案的“hackiness”表示担忧。但是,在这个问题的上下文中(即将子类型的集合转换为它们的超类型的集合)我看不到任何问题或可能的 ClassCastExceptions。无论如何,它运作良好。

        【讨论】:

          【解决方案6】:

          我不知道为什么;也许其他人可以解释这一点;但如果你这样做,它会起作用:

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

          【讨论】:

          • 我也会对此非常感兴趣。确定您没有以某种方式收到任何未经检查的警告吗?无论哪种方式,您都在扩展一个泛型类而不使子类泛型,这听起来很奇怪......
          • 是的,这很奇怪。如果你确实让子类更具体,你会得到: public class Someclass extends SomeSuperClass { @Override public Collection> getCollection() { // TODO 自动生成的方法存根 return null; } } 我以前从未使用过这样的结构,它对我来说并不是一个好方法。
          • 您的 Someclass 扩展了 SomeSuperClass,这是一个原始类型,因为 SomeSuperClass 被声明为 。我相信,由于您扩展了原始类型,因此您会收到警告,但即使它们实际上是未经检查的转换,也不会收到有关各个方法的进一步未经检查的警告。
          【解决方案7】:

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

          例如,您应该创建一些具有通用扩展名的“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 的集合

          【讨论】:

            【解决方案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】:

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

              使用以下static 方法可以使您免受有关未经检查的强制转换的警告。为了能够使用@SuppressWarnings,实际上需要在返回result 之前对result 进行看似多余的分配。

              /**
               * 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 );
              

              【讨论】:

                【解决方案10】:

                SubType 的集合不能替代 SuperType。

                【讨论】:

                • 嗯,我很清楚。我的问题是我想解决这个问题。我真正的问题是我不明白为什么 SubType 的集合不能替代SuperType。用“你不能做 X”来回答“我不能做 X,是否有解决方法”的问题,听起来你只是想在 stackoverflow 上得分。
                【解决方案11】:

                .NET 4.0 为泛型引入了协变和逆变:

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

                【讨论】:

                  猜你喜欢
                  • 2017-05-28
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2014-01-12
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2019-06-20
                  相关资源
                  最近更新 更多