Java 容器和泛型(3)HashSet,TreeSet 和 LinkedHashSet比較
一、Set回顧
一個不包括重複元素(包括可變物件)的Collection,是一種無序的集合。Set不包含滿 a.equals(b) 的元素對a和b,並且最多有一個null。
泥瓦匠的記憶宮殿:
1、不允許包含相同元素
2、判斷物件是否相同,根據equals方法
二、HashSet
一個按著Hash演算法來儲存集合中的元素,其元素值可以是NULL。它不能保證元素的排列順序。同樣,HashSet是不同步的,如果需要多執行緒訪問它的話,可以用 Collections.synchronizedSet 方法來包裝它:
Set s = Collections.synchronizedSet(new HashSet(...));
要注意的地方是,HashSet集合判斷兩個元素相等不單單是equals方法,並且必須hashCode()方法返回值也要相等。看下面的例子:
import java.util.HashSet; class EuqalsObj { public boolean equals(Object obj) { return true; } } class HashCodeObj { public int hashCode() { return 1; } } class HashSetObj { public int hashCode() { return 2; } public boolean equals(Object obj) { return true; } } public class HashSetTest { public static void main(String[] args) { HashSet objs = new HashSet(); objs.add(new EuqalsObj()); objs.add(new EuqalsObj()); objs.add(new HashCodeObj()); objs.add(new HashCodeObj()); objs.add(new HashSetObj()); objs.add(new HashSetObj()); System.out.println("HashSet Elements:"); System.out.print("/t" + objs + "/n"); } }
Run 一下,控制檯如下輸出:
HashSet Elements: [HashCodeObj@1, HashCodeObj@1, HashSetObj@2, EuqalsObj@1471cb25, EuqalsObj@3acff49f]
泥瓦匠根據結果,一一到來。首先,排列順序不定。
HashSetObj 類滿足我們剛剛的要求,所以集合中只有一個且它的HashCode值為2。
HashCodeObj 類雖然它們HashCode值為1,但是他們不相等。(其實當HashCode值一樣,這個儲存位置會採用鏈式結構儲存兩個HashCodeObj物件。)
同樣,EqualsObj 類他們相等,但是他們HashCode值不等,分別為1471cb25、3acff49f。
因此,用HashSet新增可變物件,要注意當物件有可能修改後和其他物件矛盾,這樣我們無法從HashSet找到準確我們需要的物件。
三、LinkedHashList
HashSet的子類,也同樣有HashCode值來決定元素位置。但是它使用連結串列維護元素的次序。記住兩個字:有序。
有序的妙用,複製。比如泥瓦匠實現一個HashSet無序新增,然後複製一個一樣次序的HashSet來。程式碼如下:
package com.sedion.bysocket.collection; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.Set; public class LinkedHashListTest { public static void main(String[] args) { /* 複製HashSet */ Set h1 = new HashSet<String>(); h1.add("List"); h1.add("Queue"); h1.add("Set"); h1.add("Map"); System.out.println("HashSet Elements:"); System.out.print("/t" + h1 + "/n"); Set h2 = copy(h1); System.out.println("HashSet Elements After Copy:"); System.out.print("/t" + h2 + "/n"); } @SuppressWarnings({ "rawtypes", "unchecked" }) public static Set copy(Set set) { Set setCopy = new LinkedHashSet(set); return setCopy; } }
Run 一下,控制檯輸出:
HashSet Elements: [Map, Queue, Set, List] HashSet Elements After Copy: [Map, Queue, Set, List]
可見,每個資料結構都有它存在的理由。
四、TreeSet
TreeSet使用樹結構實現(紅黑樹),集合中的元素進行排序,但是新增、刪除和包含的演算法複雜度為O(log(n))。
舉個例子吧,首先我們定義一個Bird類。(鳥是泥瓦匠最喜歡的動物)
class Bird { int size; public Bird(int s) { size = s; } public String toString() { return size + ""; } }
然後用TreeSet新增Bird類。
public class TreeSetTest { public static void main(String[] args) { TreeSet<Bird> bSet = new TreeSet<Bird>(); bSet.add(new Bird(1)); bSet.add(new Bird(3)); bSet.add(new Bird(2)); Iterator<Bird> iter = bSet.iterator(); while (iter.hasNext()) { Bird bird = (Bird) iter.next(); System.out.println(bird); } } }
Run一下,控制檯輸出如下:
Exception in thread "main" java.lang.ClassCastException: Bird cannot be cast to java.lang.Comparable at java.util.TreeMap.compare(Unknown Source) at java.util.TreeMap.put(Unknown Source) at java.util.TreeSet.add(Unknown Source) at com.sedion.bysocket.collection.TreeSetTest.main(TreeSetTest.java:29)
答案很明顯,TreeSet是排序的。所以Bird需要實現Comparable此介面。
java.lang.Comparable此介面強行對實現它的每個類的物件進行整體排序。這種排序被稱為類的自然排序,類的 compareTo 方法被稱為它的自然比較方法。
修改Bird如下:
class Bird implements Comparable<Bird> { int size; public Bird(int s) { size = s; } public String toString() { return size + "號鳥"; } @Override public int compareTo(Bird o) { return size - o.size; } }
再次Run一下:
1號鳥 2號鳥 3號鳥
五、效能測試比較
針對上面三種Set集合,我們對它們的Add方法進行效能測試:
import java.util.HashSet; import java.util.LinkedHashSet; import java.util.Random; import java.util.TreeSet; class Bird implements Comparable<Bird> { int size; public Bird(int s) { size = s; } public String toString() { return size + "號鳥"; } @Override public int compareTo(Bird o) { return size - o.size; } } public class Set { public static void main(String[] args) { Random r = new Random(); HashSet<Bird> hashSet = new HashSet<Bird>(); TreeSet<Bird> treeSet = new TreeSet<Bird>(); LinkedHashSet<Bird> linkedSet = new LinkedHashSet<Bird>(); // start time long startTime = System.nanoTime(); for (int i = 0; i < 1000; i++) { int x = r.nextInt(1000 - 10) + 10; hashSet.add(new Bird(x)); } // end time long endTime = System.nanoTime(); long duration = endTime - startTime; System.out.println("HashSet: " + duration); // start time startTime = System.nanoTime(); for (int i = 0; i < 1000; i++) { int x = r.nextInt(1000 - 10) + 10; treeSet.add(new Bird(x)); } // end time endTime = System.nanoTime(); duration = endTime - startTime; System.out.println("TreeSet: " + duration); // start time startTime = System.nanoTime(); for (int i = 0; i < 1000; i++) { int x = r.nextInt(1000 - 10) + 10; linkedSet.add(new Bird(x)); } // end time endTime = System.nanoTime(); duration = endTime - startTime; System.out.println("LinkedHashSet: " + duration); } }
Run一下,可以在控制檯中看出:
HashSet: 2610998 TreeSet: 3195378 LinkedHashSet: 2673782
可見,TreeSet因為需要進行比較,所以效能比較差。
六、總結
HashSet:equlas hashcode
LinkedHashSet:鏈式結構
TreeSet:比較,Comparable介面,效能較差
相關文章
- Java Set 常用集合 HashSet、LinkedHashSet、TreeSetJava
- java基礎:HashSet/LinkedHashSet/TreeSet — 原始碼分析Java原始碼
- HashSet vs. TreeSet vs. LinkedHashSet
- HashSet/HashMap、TreeSet/TreeMap、LinkedHashSet/LinkedHashMap 區別HashMap
- HashSet、TreeSet、CopyOnWriteArraySet和CopyOnWriteArrayList
- Java集合系列(三):HashSet、LinkedHashSet、TreeSet的使用方法及區別Java
- Go中泛型和反射比較指南Go泛型反射
- Java集合詳解7:一文搞清楚HashSet,TreeSet與LinkedHashSet的異同Java
- 比較Windows和Linux SQL容器WindowsLinuxSQL
- Java類集框架 —— HashSet、LinkedHashSet原始碼分析Java框架原始碼
- 好程式設計師Java培訓分享treeset和hashset的區別程式設計師Java
- Oracle date 型別比較和String比較Oracle型別
- Java和JavaSciprt比較Java
- Java & Go 泛型對比JavaGo泛型
- Java 中 Comparable 和 Comparator 比較Java
- 泛型類和泛型方法泛型
- TypeScript 泛型介面和泛型類TypeScript泛型
- MySQL 的 timestamp 和 datetime 型別比較MySql型別
- 4、Set集合——HashSet、TreeSet(Comparable、Comparator)
- 什麼是泛型?,Set集合,TreeSet集合自然排序和比較器排序,資料結構-二叉樹,資料結構-平衡二叉樹泛型排序資料結構二叉樹
- Java基礎鞏固第三天(泛型、ArrayList、LinkList、HashSet)Java泛型
- js 深比較和淺比較JS
- 泛型--泛型萬用字元和泛型的上下限泛型字元
- not in 和 not exists 比較和用法
- Java™ 教程(比較字串和字串的部分)Java字串
- Dalvik 和 Java 位元組碼的比較Java
- 【java】【泛型】泛型geneticJava泛型
- ABAP SICF服務和Java Servlet的比較JavaServlet
- SAP ABAP ADBC和Java JDBC的使用比較JavaJDBC
- Java,Go和Rust之間的比較 - DexterJavaGoRust
- Java HashMap 和 HashSet 的高效使用技巧JavaHashMap
- java double、float型別的比較Java型別
- TCP和UDP比較TCPUDP
- Redis 和 Memcached 比較Redis
- etcd和redis比較Redis
- Java泛型中<?> 和 <? extends Object>的異同分析Java泛型Object
- java泛型中<?>和<T>有什麼區別?Java泛型
- HashSet和HashMapHashMap
- 07.集合和泛型泛型