Java基礎之:Set——HashSet & TreeSet
HashSet
HashSet實現了Set介面(不可以重複元素),HashSet實際上底層是HashMap(看後面原始碼以及HashMap)。
HashSet不保證元素是有序的,順序取決於hash之後,再進行去索引的結果。
HashSet底層機制(hashCode + equals)
-
HashSet底層是HashMap
-
新增一個元素時,先得到此元素的hashCode值,對HashCode值進行計算得到索引值。
-
找到儲存資料表table,檢視此索引值位置上是否已經存放有元素。
-
若沒有則直接加入,若有則需要呼叫equals方法進行比較,如果相同則放棄新增(Set介面不允許重複就是這樣判斷的)。
-
若在同一個索引位上有多個元素,它們是以連結串列的形式存放的,當達到一定數量時,連結串列會自動樹化,變為紅黑樹。
簡單案例
package class_HashSet; import java.util.HashSet; public class ClassTest01{ @SuppressWarnings({ "unchecked", "rawtypes" }) public static void main(String[] args) { HashSet hashSet = new HashSet(); hashSet.add("Hello01"); hashSet.add("Hello02"); hashSet.add("Hello03"); hashSet.add("Hello04"); for(int i = 0;i<8;i++) { //將會有8個Dog物件,放在同一個索引處,形成連結串列 hashSet.add(new Dog()); } System.out.println(hashSet); } } class Dog{ @Override public int hashCode() { //讓Dog的所有例項物件的hashCode都為1 return 1; } @Override public boolean equals(Object obj) { //讓Dog的所有例項物件在比較時都返回false,即都不相同。 return false; } //當hashCode固定為1,equals為false時,會一直加入到HashSet資料表中的一個索引位上 }
實際應用案例
定義一個Employee類,該類包含:private成員屬性name(String),age(int),birthday(MyDate),
其中 birthday 為 MyDate類(屬性包括:year(int), month(int),day(int))的物件, 要求:
建立3個Employee 放入 HashSet中,當 name和birthday一樣時,認為是同一個員工, 就不能新增到HashSet集合中
提示: 根據前面HashSet 的新增機制,想辦法 重寫 Employe和MyDate的hashCode 和 equals方法
比如 “張三”, 2000-11-11
package class_HashSet; import java.util.HashSet; import java.util.Set; public class ClassWork01 { @SuppressWarnings({ "unchecked", "rawtypes" }) public static void main(String[] args) { Employee employee = new Employee("小范", 20, new MyDate(2000, 3, 26)); Employee employee2 = new Employee("小黃", 18, new MyDate(1999, 11, 25)); Employee employee3 = new Employee("小范", 20, new MyDate(2000, 3, 26)); Set set = new HashSet(); set.add(employee); set.add(employee2); set.add(employee3); for(Object obj : set) { System.out.println(obj); } } } class Employee{ private String name; private int age; private MyDate birthday; public Employee(String name, int age, MyDate birthday) { super(); this.name = name; this.age = age; this.birthday = birthday; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((birthday == null) ? 0 : birthday.hashCode()); result = prime * result + ((name == null) ? 0 : name.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Employee other = (Employee) obj; if (age != other.age) return false; if (birthday == null) { if (other.birthday != null) return false; } else if (!birthday.equals(other.birthday)) return false; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; return true; } @Override public String toString() { return "Employee [name=" + name + ", age=" + age + ", birthday=" + birthday + "]"; } } class MyDate{ private int year; private int mouth; private int day; public MyDate(int year, int mouth, int day) { super(); this.year = year; this.mouth = mouth; this.day = day; } public int getYear() { return year; } public void setYear(int year) { this.year = year; } public int getMouth() { return mouth; } public void setMouth(int mouth) { this.mouth = mouth; } public int getDay() { return day; } public void setDay(int day) { this.day = day; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + day; result = prime * result + mouth; result = prime * result + year; return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; MyDate other = (MyDate) obj; if (day != other.day) return false; if (mouth != other.mouth) return false; if (year != other.year) return false; return true; } @Override public String toString() { return year + "-" + mouth + "-" + day; } }
程式輸出:
Employee [name=小范, age=20, birthday=2000-3-26]
Employee [name=小黃, age=18, birthday=1999-11-25]
TreeSet
TreeSet實現了Set介面,所以有Set介面的所有特性。
TreeSet與HashSet不同的是,TreeSet有序的。
TreeSet可以自定義一個Comparator,定義一個排序規則。
package class_TreeSet_LinkedHashSet; import java.util.Comparator; import java.util.TreeSet; public class ClassTest01_TreeSet { @SuppressWarnings({ "rawtypes", "unchecked" }) public static void main(String[] args) { TreeSet ts = new TreeSet(new Comparator() { @Override public int compare(Object o1, Object o2) { return ((String)o1).length() - ((String)o2).length(); } }) ; //假設ts集合中放的都是字串,讓ts集合中的元素按照長度從小到大排列輸出。 ts.add("Hello"); ts.add("小范"); ts.add("xiaofan"); System.out.println(ts); } }
程式輸出:
[小范, Hello, xiaofan]