简体   繁体   English

如何使用foreach遍历混合列表?

[英]How to iterate over a mixed list using foreach?

I'm wondering how to iterate over a List with mixed contents using foreach. 我想知道如何使用foreach遍历具有混合内容的List。 See the example code below. 请参见下面的示例代码。

public class GenericsForeach {

    class A {
        void methodA() {
            System.out.println(getClass().getSimpleName() + ": A");
        }
    }

    class B extends A {
        void methodB() {
            System.out.println(getClass().getSimpleName() + ": B");
        }
    }

    void test() {

        List<A> listOfA = new ArrayList<A>();
        listOfA.add(new A());

        List<B> listOfB = new ArrayList<B>();
        listOfB.add(new B());

        List<? super A> mixed = new ArrayList<A>();
        mixed.addAll(listOfA);
        mixed.addAll(listOfB);

        Iterator<? super A> it = mixed.iterator();
        while (it.hasNext()) {
            A item = (A) it.next();
            item.methodA();
        }

        // XXX: this does not work
        // for (A item : mixed) {
        // item.methodA();
        // }
    }

    public static void main(String[] args) {
        new GenericsForeach().test();
    }
}

I construct two lists with different, but related, content types A and B ( B extends A ). 我构造了两个具有不同但相关的内容类型ABB扩展了A )。 I add the two lists to a 'mixed' list, which I declare to contain <? super A> 我将两个列表添加到“混合”列表中,声明包含<? super A> <? super A> types. <? super A>类型。 Since this mixed list is 'consuming' items of type A (or B ) I applied Bloch's PECS rule (Producer Extends, Consumer Super) to determine that I need <? super A> 由于此混合列表正在“消耗” A (或B )类型的项目,因此我应用了Bloch的PECS规则(Producer Extends,Consumer Super)确定我是否需要<? super A> <? super A> here. <? super A>在这里。

So far, so good. 到现在为止还挺好。 But now when I want to iterate over this mixed list, I can only seem to do it with an Iterator<? super A> 但是现在,当我要遍历此混合列表时,似乎只能使用Iterator<? super A>来做到这一点Iterator<? super A> Iterator<? super A> , and a cast A item = (A) it.next() . Iterator<? super A> ,然后A item = (A) it.next() When I try to use a foreach loop (see commented-out code), no joy: 当我尝试使用foreach循环(请参见注释掉的代码)时,没有任何乐趣:

Type mismatch: cannot convert from element type capture#8-of ? 类型不匹配:无法从元素类型capture#8-of转换? super GenericsForeach.A to GenericsForeach.A 超级GenericsForeach.A到GenericsForeach.A

Eclipse even helpfully offers to Eclipse甚至可以帮助提供

Change type of 'item' to '? 将“项目”的类型更改为“? super A' 超级A'

but this results in disaster: 但这会导致灾难:

for (? super A item : mixed) {
    item.methodA();
}

So I don't know. 所以我不知道 Eclipse doesn't seem to know. Eclipse似乎不知道。 Does anybody else here know if this is possible, and if it's not, why not? 在座的其他人是否知道这是否可行,如果没有,为什么呢?

You want just List<A> for mixed . 您只需要List<A>mixed My reasoning: 我的推理:

  • you want to be able to add items which are of type A , so it can't be List<? extends A> 您希望能够添加类型A ,因此它不能是List<? extends A> List<? extends A> - that would include List<B> , which you can't add an A to. List<? extends A> -包括List<B> ,您不能在其中添加A
  • you want to be able to guarantee that items which you fetch are of type A , so it can't be List<? super A> 您希望能够保证所获取的项目类型为A ,所以它不能为List<? super A> List<? super A> as that could be a List<Object> containing non-A elements. List<? super A>因为它可以是包含非A元素的List<Object>

So you end up with: 因此,您最终得到:

List<A> mixed = new ArrayList<A>();
mixed.addAll(listOfA);
mixed.addAll(listOfB);

for (A item : mixed) {
  item.methodA();
}

Everyone here is correct. 这里的每个人都是正确的。 You want use List<A> . 您要使用List<A>

But generics and assignments can be confusing, so a little more explanation is in order. 但是泛型和赋值可能会造成混淆,因此需要更多说明。

First, the problem you may have found is that you can't do this: List<A> = new List<B>() . 首先,您可能发现的问题是您无法执行以下操作: List<A> = new List<B>() The compiler won't let you assign a sub-type in to a super-type listing using generics. 编译器不允许您使用泛型将子类型分配给超类型列表。 This is a little confusing, but it prevents problems with type mis-matches. 这有点令人困惑,但是可以防止类型不匹配的问题。 (More detail can be found here: http://java.sun.com/docs/books/tutorial/java/generics/subtyping.html .) The correct terminology for this is List<? extends A> = new List<B>() (可以在这里找到更多详细信息: http : //java.sun.com/docs/books/tutorial/java/generics/subtyping.html 。)正确的术语是List<? extends A> = new List<B>() List<? extends A> = new List<B>() . List<? extends A> = new List<B>() This tells the compiler that your assignment is legal. 这告诉编译器您的分配是合法的。

At the same time, this syntax can confuse you to believing that <? extends A> 同时,此语法会使您误以为<? extends A> <? extends A> means that all elements in this variable extend A. This isn't true - the syntax just a way to inform the compiler of legal assignments. <? extends A>表示此变量中的所有元素都将A扩展。这是不正确的-语法只是一种通知编译器合法分配的方式。

So, you want to use List<A> = new List<A> and then assign the elements to List<A> using addAll() . 因此,您要使用List<A> = new List<A> ,然后使用addAll()将元素分配给List<A> This is legal because the method addAll checks to make sure each element is valid before pushing it to the collection. 这是合法的,因为方法addAll会在将每个元素推送到集合之前进行检查以确保每个元素都是有效的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM