对Java中Iterator的理解误区

声明:本博客为原创博客,未经允许,不得转载!原文链接为http://blog.csdn.net/bettarwang/article/details/28110615

      最近放假,闲来无事,便翻看以前看过的一些书,竟然发现有些书本(甚至是一些畅销书)对Java中Iterator有很大的误解,比如某畅销书在Collection那一章有这么一句话:“当使用Iterator对集合元素进行迭代时,Iterator并不是把集合元素本身传给了迭代变量,而是把集合元素的值传给了迭代变量,所以修改迭代变量的值对集合元素本身没有任何影响。”

     我们先看它举的例子,代码如下(注:原文中字符串为中文,此处按个人偏好将其翻译成了英文):

 
  1. import java.util.*;

  2.  
  3. public class IteratorTest

  4. {

  5. public static void main(String[]args)

  6. {

  7. Collection books=new HashSet();

  8. books.add("Light Java EE Practice");

  9. books.add("Crazy Java Textbook");

  10. books.add("Crazy Android Textbook");

  11.  
  12. Iterator it=books.iterator();

  13. while(it.hasNext())

  14. {

  15. String book=(String)it.next();

  16. System.out.println(book);

  17. if(book.equals("Crazy Java Textbook"))

  18. {

  19. it.remove();

  20. }

  21. book="Test String";

  22. }

  23. System.out.println(books);

  24. }

  25. }

其输出结果如下:

从这个输出结果来看:好像作者的结论挺对的。但是,其实这个结论很容易被证伪。如下面的一个例子:

 
  1. import java.util.*;

  2.  
  3. class Apple

  4. {

  5. int weight;

  6. public Apple(int weight)

  7. {

  8. this.weight=weight;

  9. }

  10. public String toString()

  11. {

  12. return "weight:"+weight;

  13. }

  14. }

  15.  
  16. public class IteratorSample

  17. {

  18. public static void main(String[]args)

  19. {

  20. Collection collection=new HashSet();

  21. Apple[]appleArray=new Apple[10];

  22. for(int i=0;i<10;++i)

  23. {

  24. appleArray[i]=new Apple(i+200);

  25. collection.add(appleArray[i]);

  26. }

  27. System.out.println(collection);

  28.  
  29. Iterator iterator=collection.iterator();

  30. Apple apple=(Apple)iterator.next();

  31. apple.weight=300;

  32. System.out.println(collection);

  33. }

  34. }

输出结果如下:


显然,collection中的第一个元素被改变了。

那么到底为什么会出现这种看起来截然相反的两种结果呢?

问题就出在String上!在我的博客深刻理解Java中final的作用(一):从final的作用剖析String被设计成不可变类的深层原因一文中就讲过String是Java中一个很特殊的类,它的特殊之外就在于它是一个不可变类,即String对象一旦生成便不可改变,经常看到的对String变量的赋值其实是让引用指向新的String对象!

       也就是说,在本文中第一个例子中,语句String book=(String)it.next();的作用只是让book也指向it.next()所指向的对象,后面book="Test String";只是让book这个引用指向一个新的字符串对象,显然这种改变不会也不可能影响原对象,it.next()所指向的另然是原来的那个对象,所以从结果来看好像作者的结论挺有道理。但是实际上Iterator.next()确实是提供了原对象的引用,对于除不可变类之外的其他对象,都可以通过这个引用来改变它(当然,也要有相应的接口)。本文中第二个例子就充分地说明了这一点,由于Apple并不是一个不可变类,故可通过iterator.next()来改变它指向的对象。

      可能有人会质疑,为什么第一个例子中就不是让it.next()这个引用指向新的对象呢?原因很简单:book和it.next()是两个独立的引用,而程序中只对book进行了赋值,并没有对it.next()进行赋值。看下面一个简单的例子即可知:

 
  1. import java.util.*;

  2.  
  3. public class StringTest

  4. {

  5. public static void main(String[]args)

  6. {

  7. String str1="I miss you";

  8. String str2=str1;

  9. System.out.println("str1:"+str1);

  10. System.out.println("str2:"+str2);

  11. str2="Will you miss me?";

  12. System.out.println("str1:"+str1);

  13. System.out.println("str2:"+str2);

  14. }

  15. }

输出结果如下:


显然,对str2的赋值根本就不影响str1,本文中第一个例子与其类似。

猜你喜欢

转载自blog.csdn.net/qfc8930858/article/details/81269427