暢銷書對Java中Iterator的理解誤區

       聲明:本博客爲原創博客,未經允許,不得轉載!原文鏈接爲http://blog.csdn.net/bettarwang/article/details/28110615

      最近放假,閒來無事,便翻看以前看過的一些書,竟然發現有些書本(甚至是一些暢銷書)對Java中Iterator有很大的誤解,比如某暢銷書在Collection那一章有這麼一句話:“當使用Iterator對集合元素進行迭代時,Iterator並不是把集合元素本身傳給了迭代變量,而是把集合元素的值傳給了迭代變量,所以修改迭代變量的值對集合元素本身沒有任何影響。

     我們先看它舉的例子,代碼如下(注:原文中字符串爲中文,此處按個人偏好將其翻譯成了英文):

import java.util.*;

public class IteratorTest
{
  public static void main(String[]args)
  {
     Collection books=new HashSet();
     books.add("Light Java EE Practice");
     books.add("Crazy Java Textbook");
     books.add("Crazy Android Textbook");
     
     Iterator it=books.iterator();
     while(it.hasNext())
     {
        String book=(String)it.next();
        System.out.println(book);
        if(book.equals("Crazy Java Textbook"))
        {
           it.remove();
        }
        book="Test String";
     }
     System.out.println(books);
   }
}
其輸出結果如下:


從這個輸出結果來看:好像作者的結論挺對的。但是,其實這個結論很容易被證僞。如下面的一個例子:

import java.util.*;

class Apple
{
  int weight;
  public Apple(int weight)
  {
    this.weight=weight;
   }
   public String toString()
   {
      return "weight:"+weight;
    }
}

public class IteratorSample
{
  public static void main(String[]args)
  {
     Collection collection=new HashSet();
     Apple[]appleArray=new Apple[10];
     for(int i=0;i<10;++i)
     {
        appleArray[i]=new Apple(i+200);
        collection.add(appleArray[i]);
     }
     System.out.println(collection);
     
     Iterator iterator=collection.iterator();
     Apple apple=(Apple)iterator.next();
     apple.weight=300;
     System.out.println(collection);
   }
}
			
輸出結果如下:


顯然,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()進行賦值。看下面一個簡單的例子即可知:

import java.util.*;

public class StringTest
{
  public static void main(String[]args)
  {
     String str1="I miss you";
     String str2=str1;
     System.out.println("str1:"+str1);
     System.out.println("str2:"+str2);
     str2="Will you miss me?";
     System.out.println("str1:"+str1);
     System.out.println("str2:"+str2);
  }
}
輸出結果如下:


顯然,對str2的賦值根本就不影響str1,本文中第一個例子與其類似。

        以前看書總是全盤接收,很少持懷疑態度,現在才發現“盡信書不如無書”,即使是暢銷書,特別是國內的一些書籍,結論未必嚴謹。帶着批判的角度去看書,多一些獨立思考,方能有更大的收穫。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章