黑马程序员技术交流社区

标题: 关于Iterator接口遍历集合的问题,想不通,求解啊! [打印本页]

作者: HM李超    时间: 2013-3-7 23:33
标题: 关于Iterator接口遍历集合的问题,想不通,求解啊!
代码如下:
import java.util.*;   
class TestIterator2
{
    public static void sop(Object obj)
    {
        System.out.println(obj);
    }
    public static void main(String[] args)
    {
        Collection books = new HashSet();
        books.add("aaa");
        books.add("bbb");
        books.add("ccc");
        books.add("ddd");
        
        sop("原集合是:"+books);

        Iterator it = books.iterator();
        
        while(it.hasNext())
        {
            String book = (String)it.next();
            sop(book);

            if(book.equals("bbb"))
            book="eee";           //1
        }
        sop("遍历操作后的集合是:"+books);
    }
}
输入结果如下:
原集合是:[aaa, ddd, ccc, bbb]
aaa
ddd
ccc
bbb
遍历操作后的集合是:[aaa, ddd, ccc, bbb]

问题:Iterator遍历集合时,我定义了一个字符串book,用来保存遍历的结果,我原想把bbb转换成eee,
          但是,打印出来的结果却是和原集合保存的数据相同,说明集合数据没有任何变化,这是为什么?Iterator
          对集合进行迭代时,迭代变量it保存的应该不是集合本身吧?


作者: 谢洋    时间: 2013-3-7 23:57
while(it.hasNext())
        {
            String book = (String)it.next();//这果只是把集中的某元素赋给book字符串
            sop(book);

            if(book.equals("bbb"))
            book="eee";           //1 而这里把字符串的引用指向"eee"这相字符串,这个过程跟集合里的元素无无关,只是知道集合中会有这么一个元素,当然不会被改变
        }
        sop("遍历操作后的集合是:"+books);
“对集合进行迭代时,迭代变量it保存的应该不是集合本身吧?”我觉得是这样的
可以把迭代器理解成,只是操作集合元素的一个工具;但这个工具被集合合生成时会记住集合的一些信息,
如集个元素的个数等等
作者: 谢玉成    时间: 2013-3-8 00:08
     Iterator 是在HashSet集合里实现的,而HashSet里的 Iterator 的底层确是HashMap里的 public Set<K> keySet();所以当你使用Iterator 遍历HashSet里的值时,动的根本不是源集合里的值,而是可以理解为HashSet的一个副本,所以Iterator 只能用来遍历集合,不能对源集合进行操作...
作者: 移动小坦克    时间: 2013-3-8 00:41
本帖最后由 韩松范 于 2013-3-8 00:43 编辑

String book = (String)it.next();
book只是一个局部变量,接收到的是集合中,元素的value,也就是一个字符串
所以改变book的值,根本不会影响集合中的元素。

如果想改变,只能先把“bbb”,在集合众删除,再在集合中添加“eee"
由于hashSet元素是无序的,且存放的为值由哈希值所决定,
所以"bbb",和”eee“存放的位置不同
代码如下


            public static void sop(Object obj)
            {
                System.out.println(obj);
            }
            public static void main(String[] args)
            {
                Collection books = new HashSet();
                books.add("aaa");
                books.add("bbb");
                books.add("ccc");
                books.add("ddd");
               
                sop("原集合是:"+books);

                Iterator it = books.iterator();
               
                while(it.hasNext())
                {
                    String book = (String)it.next();
                    sop(book);

                    if(book.equals("bbb"))
                    {
                            books.remove("bbb");
                            books.add("eee");
                    }
                           
                    
                }
                sop("遍历操作后的集合是:"+books);
            }

打印结果:
原集合是:[aaa, ddd, ccc, bbb]
aaa
ddd
ccc
bbb
遍历操作后的集合是:[aaa, ddd, ccc, eee]//这里虽然eee被打印的顺序和bbb一样都是在最后,但是实际上由于它们的哈希值不同,所以存放位置不同。

作者: 黑马李超    时间: 2013-3-8 00:58
本帖最后由 黑马李超 于 2013-3-8 01:01 编辑

楼上的代码我验证了下,确实可以输出,但是只是偶然。如果删除的不是"bbb",就会马上抛出ConcurrentModificationException。
因为在迭代器生成时,就已经产生了一个索引,然后按照这个索引进行遍历。如果在遍历的过程中,使用集合的方法对集合进行操作,就会
使迭代器发生异常。这时只可以使用迭代器的自有方法进行remove操作,然后再遍历结束后再往集合里添加新元素即可。
  1. public static void sop(Object obj)
  2.             {
  3.                 System.out.println(obj);
  4.             }
  5.             public static void main(String[] args)
  6.             {
  7.                 Collection books = new HashSet();
  8.                 books.add("aaa");
  9.                 books.add("bbb");
  10.                 books.add("ccc");
  11.                 books.add("ddd");
  12.                
  13.                 sop("原集合是:"+books);

  14.                 Iterator it = books.iterator();
  15.                
  16.                 while(it.hasNext())
  17.                 {
  18.                     String book = (String)it.next();
  19.                     sop(book);

  20.                     if(book.equals("aaa"))
  21.                     {
  22.                             it.remove();//可以使用迭代器自有方法remove()      
  23.                     }
  24.                            
  25.                     
  26.                 }

  27.                                 books.add("eee");//遍历结束后再添加新元素
  28.                 sop("遍历操作后的集合是:"+books);
复制代码

作者: amen0205    时间: 2013-3-8 02:05
简单的说  在1处  因为你只是把''eee"  的值赋值给了 book   这样原来book指向"bbb", 后来指向"eee"   对"bbb"  有影响吗 没有

如果你要用HashSet  来存放 对象 那这里我建议你先用  remove 吧  ”bbb“  移除   再添加”eee“   因为在HashSet里面  对象的排序  有自己的规律 你干涉不了  如果你想用"eee"替换"bbb"的位置  不行的  换不了 至少我现在不知道怎么换  
作者: 谢洋    时间: 2013-3-8 08:36
韩松范 发表于 2013-3-8 00:41
String book = (String)it.next();
book只是一个局部变量,接收到的是集合中,元素的value,也就是一个字符 ...

你上面的做法有问题
1、在迭代时,使用集合的方式进添删会有可能抛出异常的,
   但使用迭代器的方式添删就不会出问题,但只有ListIterator才有这功能。
2、为什么在迭代时,使用集合的方式进添删会有可以抛出异常?
原因是:先明确迭代器相当于操作集合的工具
a、迭代器时由其对应的集合产生的,也就是说迭代器本身内部记录着产生他的集合的一些信息
,如集个元素的个数等等。
b、当迭代器产生后,它里面的信息内容就相对于其对应的集合是独立的,
假设迭代器记住集合的元素个数是5,当我们在迭代时,同时用集合的方式添加或减少元素,
那么这时候集合中实际的元素个数不再是5了,而迭代器记录的信息又相对集合来说是独立的,
那么迭代器就还是认为集合中还是有五个元素,这样就有可能发异常。

作者: 移动小坦克    时间: 2013-3-8 12:56
谢洋 发表于 2013-3-8 08:36
你上面的做法有问题
1、在迭代时,使用集合的方式进添删会有可能抛出异常的,
   但使用迭代器的方式添删 ...

谢谢不吝赐教,学习了。。。




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2