1、set接口
(1)特點
- 元素不能重復(equals判斷)
- 無序
@Test public void test1() { Set set=new HashSet(); set.add("zhai"); set.add("123"); set.add("null"); set.add("123"); set.add("90"); System.out.println(set); }
[123, null, 90, zhai]
注意:Treeset不允許添加null元素
(2)特有方法
沒有特有方法,主要是從collection接口繼承來的
(3)遍歷方式
和collection接口的遍歷方式相同:迭代器、增強for
2、HashSet底層結構
(1)底層結構
- 哈希表
public HashSet() { map = new HashMap<>(); }
因為HashSet維護的是一個HashMap對象,而HashMap維護的是一個哈希表,兩者都是基於hash結構的。
- 無序:根據哈希值確定元素在哈希表中的位置
(2)去除重復原理
原理:
先獲取元素的哈希值,通過一些運算獲取一個整數索引index(要存放在數組的位置)
如果索引處沒有元素,則直接添加
如果索引處有其他元素,則需要進行equals判斷,如果不相等,則以鏈表的形式追加到已有元素的后面並返回true,如果相等則直接覆蓋並返回false
如果不是哈希表的結構,需要進行大量的equals判斷,哈希表的使用大大減少了equals的使用
重寫equals與hashCode方法(https://www.cnblogs.com/zhai1997/p/11354885.html)
存儲已經存在的數據類型的數據,不用重寫equals和hashcode方法,即可去除重復元素
存儲自定義類型的數據需要重寫equals和hashcode方法
3、TreeSet底層結構
(1)底層結構
基於map對象(TreeMap),treeMap的底層是紅黑樹的結構,可以實現對元素的排序。
(2)特點
- 不允許重復
- 可以實現對里面的元素進行排序(自然排序、定制排序)
- 紅黑樹存儲的時候是左邊的存較小的元素,右邊存儲較大的元素,取出的時候可以按順序取出,先取出20,然后25... ...
- 紅黑樹與二叉樹的不同是,紅黑樹給二叉樹標記了顏色,例如:左邊紅色右邊黑色,當左邊的紅色元素過多右邊黑色元素過少的時候,紅黑樹就失去了平衡,此時就要重新打亂順序重新選出根元素,使得兩邊保持平衡
- 紅黑樹是二叉樹的一種
(3)TreeSet的使用
@Test public void test1() { Set set=new TreeSet(); set.add(new Student("zhai",12)); set.add(new Student("zz",13)); set.add(new Student("zhang",14)); set.add(new Student("liu",19)); set.add(new Student("zhang",14)); for (Object s: set){ System.out.println(s); } }
java.lang.ClassCastException: com.zhb.domain.Student cannot be cast to java.lang.Comparable
報錯的類型是類型轉換異常,原因是添加元素的時候在確定元素在二叉樹中的位置的時候,需要當前元素與結點元素進行比較,小的左,大的右,相等的話不添加,但是對象不具有比較性,因此報錯
要讓其具有比較性有兩種方法:
自然排序:
public class Student implements Comparable{ public String sname; public int age; @Override public String toString() { return "Student{" + "sname='" + sname + '\'' + ", age=" + age + '}'; } public Student(String sname, int age) { this.sname = sname; this.age = age; } public String getSname() { return sname; } public void setSname(String sname) { this.sname = sname; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public int compareTo(Object o) { Student s=(Student)o; return Integer.compare(this.age,s.age); } }
Student{sname='zhai', age=12} Student{sname='zz', age=13} Student{sname='zhang', age=14} Student{sname='liu', age=19}
此方法需要實現接口重寫方法
定制排序:
@Test public void test1() { Set set=new TreeSet(new Comparator() { @Override public int compare(Object o1, Object o2) { Student s1=(Student)o1; Student s2=(Student)o2; return Integer.compare(s1.getAge(),s2.getAge()); } }); set.add(new Student("zhai",12)); set.add(new Student("zz",13)); set.add(new Student("zhang",14)); set.add(new Student("liu",19)); set.add(new Student("zhang",14)); for (Object s: set){ System.out.println(s); } }
Student{sname='zhai', age=12} Student{sname='zz', age=13} Student{sname='zhang', age=14} Student{sname='liu', age=19}
在定義TreeSet的同時定義比較器
(4)添加方法原理
底層是treemap的添加:
進行元素的比較:
調用的比較器:
(5)如何實現去重
通過比較方法(compareTo方法)的返回值是否為0來判斷元素是否重復。一般Set會比較equals和hashCode。而TreeSet還會比較compareTo,先調用compareTo並通過二分法將元素排列以后,再調用equals和hashCode來判斷和當前排列位置的元素是否一致
4、LinkedHashSet
LinkedHashSet和LinkedHashMap在Java里也有着相同的實現,前者僅僅是對后者做了一層包裝,也就是說LinkedHashSet里面有一個LinkedHashMap(適配器模式)
結構:哈希表,鏈表部分是雙向鏈表
好處:保證迭代順序跟插入順序相同、迭