<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    周浩

      BlogJava :: 首頁 :: 新隨筆 :: 聯系 ::  :: 管理 ::
      28 隨筆 :: 0 文章 :: 16 評論 :: 0 Trackbacks

    Java 容器類學習心得

    一心得

    1.? 接口
    整個 Java 容器類的基礎是容器接口(例如 Collection Map 等接口),而不是類。使用接口的最大好處在于將容器的實現與容器的接口分開,這就意味著你可以使用相同的方法訪問容器而不用關心容器是由什么樣的數據結構實現的。同樣, Iterator 接口也使得用戶可以使用相同的方法訪問不同的容器類。以上這些是通用算法的基礎。

    1.1?Collection 接口
    Collection
    接口有如下基本方法:
    boolean add(Object obj)
    :如果添加對象后,集合確實發生了變化,則返回 true ;否則返回 false
    Iterator iterator()
    :返回一個實現了 Iterator 接口的對象
    此外,還有
    int size(),boolean isEmpty()
    boolean contains(Object obj) void clear() 等許多有用的方法

    1.2?Map 接口
    Map
    用于存放關鍵字 / 值對。有如下基本方法:
    Object get(Object key)
    Object put(Object key,Object balue)
    Set keySet()
    Set entrySet()
    此外,還有其他有用的方法。
    需要注意的是,從表面看它似乎就是一種由鍵值對構成的集合,但實際上并不是這樣。不過另一方面假如將 Map 的某一部分看作集合,有時候也還是顯得非常方便的。換言之你可以創建一個集合用它來表達 Map 的那一部分。綜上所述,一個 Map 可以返回的東西包括它的鍵值構成的一個 Set 、由它的值構成的一個集合或者由它的鍵值對構成的一個 Set

    1.3?Iterator 接口
    Iterator
    接口有下面 3 個基本方法:
    Object next()
    :返回迭代器剛越過的元素的引用
    boolean hasNext()
    :判斷容器內是否還有可供訪問的元素
    void remove()
    :刪除迭代器剛越過的元素
    注意: Java 中的迭代器與 STL 中的迭代器在概念上有很重要的區別。在 STL 中,迭代器類似于數組的索引,使用這種迭代器可以查看存放在該位置上的元素(類似于通過數組索引 i 來訪問 c[i] 一樣)。 Java 中的迭代器并不這樣運行。查看與位置的變化緊密的結合在一起。每次通過 next() 訪問一個元素的同時,迭代器的位置會自動向前走一步。
    這個問題可以這樣理解: Java 中的迭代器指向的位置并不是元素,而是元素之間。這樣,每次調用 next() 時,迭代器便越過下一個元素,同時返回它剛越過的那個元素的引用。
    根據上面的說明,很容易得出下面的代碼是錯誤的:
    it.remove();
    it.remove();
    而下面的代碼是正確的:
    it.remove();
    it.next();
    it.remove();
    迭代器的典型應用
    Iterator it=c.iterator();
    while(it.hasNext())
    {
    ?Object obj=it.next();
    ?//do something with obj
    }

    1.4? 子接口
    1.4.1?List
    接口
    List
    Collection 接口中分立出來是因為 List 的特點——有序的集合。這里指的有序并不是按照大小排好序的( Sorted ),而是指集合是可以以確定的順序訪問的序列。針對 List 的這個特點,它比 Collection 接口增加了通過索引進行操作的方法。例如, add remove get set 等方法的參數表中都可以加入索引的數值,從而操作處在索引位置處的元素。

    1.4.2?Set 接口
    Set
    List 的不同,它里面的元素是無序的;所以,不能通過任何索引的方法來操作 Set 對象

    1.4.3?ListIterator 接口
    使用與 List 的迭代器,比 Iterator 接口增加了一些方法(例如 add() 等)。此外,由于 List 是雙向表,所以還增加了 Object previous() boolean hasPrevious() 方法,用法與 next() hasNext() 一樣。

    1.4.4?SortedMap 接口
    包含如下基本方法:
    Comparator comparator()
    Object firstKey()
    Object lastKey()

    2.? 抽象容器類
    2.1?
    抽象容器類包括 AbstractCollection AbstractList AbstractSet 等等

    2.2? 為什么要有抽象結合類?
    例如 Collection 接口中定義了許多有用的方法,如果實現 Collection 接口的每個類都自行實現這么多的方法,那將是非常麻煩的。為了使實現 Collection 接口的類的實現更容易, AbstractCollection 類讓一些基本方法(比如 add() iterator() )變成了抽象的方法,而利用這些基本方法的其他方法(例如 addAll() 等等)則具體實現了。

    3.? 具體的容器
    3.1?ArrayList
    LinkedList
    都是實現了 List 接口的類,是有序集。 List 接口支持通過索引的方法來訪問元素,對于這一點, ArrayList 沒有任何問題;但是對于 LinkedList 則有很大的問題,鏈表本身不應該支持隨機存儲,但是作為 List 的一個實現,鏈表也提供了對隨機訪問的支持,但是效率很低。每次通過索引的方法都是進行一次遍歷。我認為,其實就不應該讓鏈表支持隨機訪問;而 Java 這樣實現我想是因為整個集合框架的體系,使得鏈表與數組可以使用同樣的方法使用。綜上所述,對于 LinkedList 最好不使用隨機訪問,而使用迭代器。

    3.2?TreeSet
    3.2.1?TreeSet
    SortedSet 的一個實現。根據數據結構的知識可以知道,樹的效率非常高,而且 Java 標準庫中有 TreeSet 這樣的類,以后應該盡量使用 TreeSet 來提高程序的效率。
    3.2.2?
    需要注意的是: TreeSet 作為有序集,它通過 compareTo 或者 Comparator 來將集合元素排序。任何具有相同比較值的元素(無論它們是否 equals() ),在 TreeSet 中都作為同一個元素,從而不能有重復。這樣以來,即使是不同的對象也不能加入到集合中,這一點有時候很不方便。我在編寫 A* 算法時,不同狀態有時候對應著同一個啟發函數值,那么這些不同的狀態就無法加入到 TreeSet 中。

    3.3?HashSet
    3.3.1?HashSet
    是非常高效的數據結構,與 TreeSet 不同, HashSet 是比較對象的 equals() 方法來區分不同的對象。這樣只有真正不同的對象才能不被重復的加入到集合中。
    3.3.2?
    需要注意的是: HashSet 效率非常高,但是對象的 hashCode 函數不好確定。一般默認的對象的 hashCode 函數是根據對象的內存地址得到的。好的 hashCode 函數是 HashSet 成功運用的關鍵。

    4.? 視圖
    4.1?
    什么是視圖?
    對映象類使用 keySet() 方法,仿佛該方法建立了一個新的集合,并將影響的所有關鍵字都填入這個集合。實際情況并非如此,對這個集合的任何操作都將反映到原始的映象對象上。
    實際上, keySet() 返回的是一個實現 Set 接口的對象,對該對象的操作就是對映象的操作。這樣的集合成為視圖。
    4.2?
    視圖的應用
    4.2.1?
    將現有的容器變為線程安全的容器:使用 Collections.synchronizedCollection(Collection c) 方法,在 SDK 文檔中該方法的解釋是“ Returns a synchronized (thread-safe) collection backed by the specified collection ”。
    4.2.2?
    將現有的容器變為只讀的容器:使用 Collections.unmodifiableCollection(Collection c) 方法,在 SDK 文檔中該方法的解釋是“ Returns an unmodifiable view of the specified collection. ”。
    4.2.3?
    子范圍
    4.2.4?Arrays
    類中的 asList() 方法


    5.?
    通用算法
    通用的集合接口帶來的一大好處就是可以編寫通用算法。可以使用 Collections 中的靜態通用方法,也可以編寫自己的通用方法。
    (具體的算法的內容在此略去)


    總結:千萬記住這句話——沒有最好的容器(數據結構),要根據不同的問題選擇不同的容器,以此來達到功能的要求和效率的最優。

    二、 Java2 中的容器類庫

    Java1.2 之后 Java 版本統稱為 Java2 Java2 中的容器類庫才可以說是一種真正意義上的集合框架的實現。基本完全重新設計,但是又對 Java1 中的一些容器類庫在新的設計上進行了保留,這主要是為了向下兼容的目的,當用 Java2 開發程序時,應盡量避免使用它們, Java2 的集合框架已經完全可以滿足你的需求。有一點需要提醒的是,在 Java1 中容器類庫是同步化的,而 Java2 中的容器類庫都是非同步化,這可能是對執行效率進行考慮的結果。
    Java2
    中的集合框架提供了一套設計優良的接口和類,使程序員操作成批的數據或對象元素極為方便。這些接口和類有很多對抽象數據類型操作的 API ,而這是我們常用的且在數據結構中熟知的。例如 Maps Sets Lists Arrays 等。并且 Java 用面向對象的設計對這些數據結構和算法進行了封裝,這就極大的減化了程序員編程時的負擔。程序員也可以以這個集合框架為基礎,定義更高級別的數據抽象,比如棧、隊列和線程安全的集合等,從而滿足自己的需要。
    Java2
    的集合框架,抽其核心,主要有三類: List Set Map 。如下圖所示:

    從圖上可以看出, List Set 繼承了 Collection ,而 Map 則獨成一體。初看上去可能會對 Map 獨成一體感到不解,它為什么不也繼承 Collection 呢?但是仔細想想,這種設計是合理的。一個 Map 提供了通過 Key Map 中存儲的 Value 進行訪問,也就是說它操作的都是成對的對象元素,比如 put() get() 方法,而這是一個 Set List 所不就具備的。當然在需要時,你可以由 keySet() 方法或 values() 方法從一個 Map 中得到鍵的 Set 集或值的 Collection 集。
    1
    Collection 接口提供了一組操作成批對象的方法,用 UML 表示的方法列表如下:
    它提供了基本操作如添加、刪除。它也支持查詢操作如是否為空 isEmpty() 方法等。為了支持對 Collection 進行獨立操作, Java 的集合框架給出了一個 Iterator ,它使得你可以泛型操作一個 Collection ,而不需知道這個 Collection 的具體實現類型是什么。它的功能與 Java1 中的 Enumeration 類似,只是更易掌握和使用,功能也更強大。在建立集合框架時, Sun 的開發團隊考慮到需要提供一些靈活的接口,用來操作成批的元素,又為了設計的簡便,就把那些對集合進行可選操作的方法與基本方法放到了一起。因為一個接口的實現者必須提供對接口中定義的所有方法的實現,這就需要一種途徑讓調用者知道它正在調用 ? 的可選方法當前不支持。最后開發團隊選擇使用一種信號,也即拋出一種不支持操作例外 (UnsupportedOperationException) ,如果你在使用一個 Collection 中遇到一個上述的例外,那就意味著你的操作失敗,比如你對一個只讀 Collection 添加一個元素時,你就會得到一個不支持操作例外。在你實現一個集合接口時,你可以很容易的在你不想讓用戶使用的方法中拋出 UnsupportOperationException 來告訴使用者這個方法當前沒有實現, UnsupportOperationException RuntimeException 的一個擴展。
    另外 Java2 的容器類庫還有一種 Fail?fast 的機制。比如你正在用一個 Iterator 遍歷一個容器中的對象,這時另外一個線程或進程對那個容器進行了修改,那么再用 next() 方法時可能會有災難性的后果,而這是你不愿看到的,這時就會引發一個 ConcurrentModificationException 例外。這就是 fail fast
    2
    List 接口對 Collection 進行了簡單的擴充,它的具體實現類常用的有 ArrayList LinkedList 。你可以將任何東西放到一個 List 容器中,并在需要時從中取出。 ArrayList 從其命名中可以看出它是一種類似數組的形式進行存儲,因此它的隨機訪問速度極快,而 LinkedList 的內部實現是鏈表,它適合于在鏈表中間需要頻繁進行插入和刪除操作。在具體應用時可以根據需要自由選擇。前面說的 Iterator 只能對容器進行向前遍歷,而 ListIterator 則繼承了 Iterator 的思想,并提供了對 List 進行雙向遍歷的方法。
    3
    Set 接口也是 Collection 的一種擴展,而與 List 不同的時,在 Set 中的對象元素不能重復,也就是說你不能把同樣的東西兩次放入同一個 Set 容器中。它的常用具體實現有 HashSet TreeSet 類。 HashSet 能快速定位一個元素,但是你放到 HashSet 中的對象需要實現 hashCode() 方法,它使用了前面說過的哈希碼的算法。而 TreeSet 則將放入其中的元素按序存放,這就要求你放入其中的對象是可排序的,這就用到了集合框架提供的另外兩個實用類 Comparable Comparator 。一個類是可排序的,它就應該實現 Comparable 接口。有時多個類具有相同的排序算法,那就不需要在每分別重復定義相同的排序算法,只要實現 Comparator 接口即可。
    集合框架中還有兩個很實用的公用類: Collections Arrays Collections 提供了對一個 Collection 容器進行諸如排序、復制、查找和填充等一些非常有用的方法, Arrays 則是對一個數組進行類似的操作。
    4
    Map 是一種把鍵對象和值對象進行關聯的容器,而一個值對象又可以是一個 Map ,依次類推,這樣就可形成一個多級映射。對于鍵對象來說,像 Set 一樣,一個 Map 容器中的鍵對象不允許重復,這是為了保持查找結果的一致性 ; 如果有兩個鍵對象一樣,那你想得到那個鍵對象所對應的值對象時就有問題了,可能你得到的并不是你想的那個值對象,結果會造成混亂,所以鍵的唯一性很重要,也是符合集合的性質的。當然在使用過程中,某個鍵所對應的值對象可能會發生變化,這時會按照最后一次修改的值對象與鍵對應。對于值對象則沒有唯一性的要求。你可以將任意多個鍵都映射到一個值對象上,這不會發生任何問題(不過對你的使用卻可能會造成不便,你不知道你得到的到底是那一個鍵所對應的值對象)。 Map 有兩種比較常用的實現: HashMap TreeMap HashMap 也用到了哈希碼的算法,以便快速查找一個鍵, TreeMap 則是對鍵按序存放,因此它便有一些擴展的方法,比如 firstKey(),lastKey() 等,你還可以從 TreeMap 中指定一個范圍以取得其子 Map 。鍵和值的關聯很簡單,用 pub(Object?key,Object?value) 方法即可將一個鍵與一個值對象相關聯。用 get(Object?key) 可得到與此 key 對象所對應的值對象。

    三、未來的 Java 容器類庫

    前面幾部分對 Java 中容器類庫的過去與現在的狀況進行了討論,然而就在寫下此文時, Sun 已經開始通過某種途徑分發 J2SE1.5 Alpha 測試版了。在今年的 JavaOne 大會上,諸多大師描繪了 Java 的美好未來與在下一個版本中即將加入的一些新特性,其中為容器類庫加入的一個重要特性就是泛型。
    其實泛型并不是什么新東西,在其它一些面向對象的語言中早已存在,如 C++ 。泛型的基本目標很簡單:能夠保證你使用一種類型安全的容器。那么到底怎樣一種類型安全呢?我們先看下面這一段沒有使用泛型特性的代碼:

    1.??? import ?java.util.*;

    2.??? public ?class?Generics{

    3.??? ????/**

    4.??? ?????*? 輸出一個 String 類型的列表,假設所給參數 list 中所有元素都為 String

    5.??? ?????*/

    6.??? ????public?static?void?printList(List?list){

    7.??? ????????for(int?i=0;i<list.size();i++){

    8.??? ????????????System.out.println(((String)list.get(i)).toString());

    9.??? ????????}

    10.?? ????}

    11.?? ????public?static?void?main(String[]?args){

    12.?? ????????List?list=new?ArrayList();

    13.?? ????????for(int?i=0;i<9;i++){

    14.?? ????????????list.add("Number:"+Integer.toString(i));

    15.?? ????????}

    16.?? ????????//list.add(new?Generics());??//(1)

    17.?? ????????printList(list);

    18.?? ????}

    19.?? }

    上面的代碼很簡單,定義了一個靜態方法來打印一個元素為 String 類型的 List ,然而正如你看到的一樣,如果你試著將 (1) 行中前面的注釋去掉,你就會得到一個 ClassCastException 例外,因為 printList 會將 list 中的每個元素都轉型為 String ,而在遇到最后一個元素時發現它是一個 Generics 類型從而無法完成轉型,例外就被拋出。這種情況在 Java 編程中很容易出現,原因是 Java 的容器類庫通常保存的是 Object 類型,而這是所有類的直接或間接超類,這就允許你將任何類型的元素添加到一個 List 中而不會給你任何提示,有經驗的程序員可能會自己編寫一個容器類來限制添加到其中的元素,這是一個編程技巧。但是現在我們就再也不用那樣做了,泛型機制會為我們做好這件事。那就看一下用泛型機制對上面代碼進行的改進:

    1.??? import ?java.util.*;

    2.??? public ?class?Generics{

    3.??? ????/**

    4.??? ?????*? 輸出一個 String 類型的列表,限制了所給參數 list 中所有元素都為 String

    5.??? ?????*/

    6.??? ????public?static?void?printList(ArrayList<String>?list){

    7.??? ????????for(int?i=0;i<list.size();i++){

    8.??? ????????????System.out.println(list.get(i).toString());

    9.??? ????????????//get() 返回的不再是 Object 類型,而是 String 類型

    10.?? ????????}

    11.?? ????}

    12.?? ????public?static?void?main(String[]?args){

    13.?? ????????ArrayList?list=new?ArrayList<String>();?// 注意此行中聲明語法的變化

    14.?? ????????for(int?i=0;i<9;i++){

    15.?? ????????????list.add("Number:"+Integer.toString(i));?// 只能向其中添加 String 類型

    16.?? ????????}

    17.?? ????????list.add(new?Generics());??// 無法通過,編譯時錯誤

    18.?? ????????printList(list);

    19.?? ????}

    1. }
      正如在代碼中所看到的,容器的聲明有了變化,即在一個容器類后面用 <> 來說明你想要放入這個容器中的元素類型,那么接下來你只能向這個容器加那種類型,否則編譯就無法通過。在 printList 中也省去了轉型的麻煩。當然有了泛型,并不是說以前的聲明方法不能用了,你完全可以還用以前的方法,這沒有任何問題。其實根據 JSR 中對 for 語句功能的增強,遍歷一個容器也會更加簡單。
      當然泛型的使用方法不只如此,這里并沒有對它進行完整描述,只想告訴你,泛型確實為我們編程提供了便利,但是仍然需要用心去學習和掌握。
      隨著 Java 的進一步完善,它的功能和易用性也得到提高,我有理由相信 Java 在計算機語言中所占的位置也會更加牢固,讓喜愛 Java 的人更加喜愛它。祝愿 Java 一路走好!
    posted on 2006-04-28 16:23 Derek 閱讀(6445) 評論(0)  編輯  收藏

    只有注冊用戶登錄后才能發表評論。


    網站導航:
     
    Google
    主站蜘蛛池模板: 一区二区三区免费高清视频| 99re在线精品视频免费| 亚洲永久无码3D动漫一区| 永久免费av无码入口国语片| 亚洲中文久久精品无码1| 四虎影院永久免费观看| 野花香在线视频免费观看大全| 亚洲人成伊人成综合网久久| 国产男女性潮高清免费网站| 国产免费阿v精品视频网址| 亚洲a级在线观看| 亚洲一区精品伊人久久伊人| 免费人成在线观看69式小视频| 美女被免费网站视频在线| 亚洲午夜视频在线观看| 日韩高清在线高清免费| 久久久久久国产精品免费免费男同 | 国产亚洲精品成人a v小说| 999久久久免费精品国产 | 久久精品免费一区二区喷潮| 国产精品青草视频免费播放| 亚洲av永久无码嘿嘿嘿| 国产美女亚洲精品久久久综合| 久久久久久久免费视频| 中文字幕不卡免费视频| 亚洲欧美第一成人网站7777| 亚洲国产成人精品不卡青青草原| 国产真人无遮挡作爱免费视频| 精品免费久久久久久久| 久久久WWW成人免费精品| 亚洲欧美aⅴ在线资源| 亚洲成人在线免费观看| 亚洲美女又黄又爽在线观看| 在线免费观看国产视频| 国产乱子精品免费视观看片| 国产精品一区二区三区免费| 亚洲精品无码你懂的| 亚洲免费在线视频播放| 亚洲国产女人aaa毛片在线| 中文字幕亚洲一区二区三区| 国产成人在线免费观看|