十 Java集合框架(2):Set接口
生活随笔
收集整理的這篇文章主要介紹了
十 Java集合框架(2):Set接口
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
文章目錄
- Set接口和常用方法
- 基本介紹
- set接口常用方法
- set接口的遍歷方式
- Set實現類--HashSet
- 基本介紹
- HashSet底層機制
- 源碼分析
- HashSet的add方法
- HashSet擴容機制
- 代碼實踐
- Set實現類--LinkedHashSet
- 基本介紹
- 源碼分析
- Set實現類--TreeSet
- 基本介紹
- 源碼分析
課程視頻:https://www.bilibili.com/video/BV1YA411T76k
Set接口和常用方法
基本介紹
無序(添加和取出的順序不一致),沒有索引
不允許重復元素,所以最多包含一個null
JDK API中Set接口的實現類有
set接口常用方法
和List接口一樣,set接口也是Collection的子接口,因此,常用方法和Collection接口一樣。
| boolean | add(E e)如果指定的元素不存在,則將其指定的元素添加(可選操作)。 |
| boolean | addAll(Collection<? extends E> c)將指定集合中的所有元素添加到此集合(如果尚未存在)(可選操作)。 |
| void | clear()從此集合中刪除所有元素(可選操作)。 |
| boolean | contains(Object o)如果此集合包含指定的元素,則返回 true 。 |
| boolean | containsAll(Collection<?> c)返回 true如果此集合包含所有指定集合的元素。 |
| boolean | equals(Object o)將指定的對象與此集合進行比較以實現相等。 |
| int | hashCode()返回此集合的哈希碼值。 |
| boolean | isEmpty()如果此集合不包含元素,則返回 true 。 |
| Iterator<E> | iterator()返回此集合中元素的迭代器。 |
| boolean | remove(Object o)如果存在,則從該集合中刪除指定的元素(可選操作)。 |
| boolean | removeAll(Collection<?> c)從此集合中刪除指定集合中包含的所有元素(可選操作)。 |
| boolean | retainAll(Collection<?> c)僅保留該集合中包含在指定集合中的元素(可選操作)。 |
| int | size()返回此集合中的元素數(其基數)。 |
| default Spliterator<E> | spliterator()在此集合中的元素上創建一個 Spliterator 。 |
| Object[] | toArray()返回一個包含此集合中所有元素的數組。 |
| <T> T[] | toArray(T[] a)返回一個包含此集合中所有元素的數組; 返回的數組的運行時類型是指定數組的運行時類型。 |
set接口的遍歷方式
同Collection的遍歷方法一樣,因為set接口是Collection接口的子接口。
Set實現類–HashSet
基本介紹
HashSet 實現了Set接口
HashSet 實際上是HashMap(源碼如下)
public HashSet() {map = new HashMap<>(); }可以存放null值,但是只能有一個null
HashSet不保證元素是有序的,取決于hash值,再確定索引的結果
不能有重復元素/對象
HashSet底層機制
HashSet 底層是HashMap,HashMap底層是(數組+鏈表+紅黑樹)
相較數組存儲效率高
代碼實現
//模擬一個HashSetMap的底層(HashMap的底層結構)//1.創建一個數組,數組的類型是Node[] //2.有些人,直接把Node[]數組稱為表 Node[] table = new Node[16];//3.創建結點 Node john = new Node("john",null); table[2] = john; Node jack = new Node("jack", null); john.next = jack;//將jack節點掛載到 john后 Node rose = new Node("Rose",null); jack.next = rose;//將roes結點掛載到jack后 Node lucy = new Node("lucy", null); table[3] = lucy; System.out.println(table);存儲結構
源碼分析
HashSet的add方法
HashSet擴容機制
注意:
- 每添加一個元素(包括在table表,與表中鏈表)即添加一個節點,會執行一次 ++size,當size > threshold 時就會執行擴容。
- table表擴容并不是表的16個大小被添加完才執行,當所有元素的個數大于臨界值時就會執行擴容。
具體可以查看博客 https://blog.csdn.net/weixin_39667787/article/details/86678215
代碼實踐
題目描述:
定義一個Eeployee類,該類包括:private成員屬性name,age
關鍵:重寫hashCode()與equals()方法
快捷鍵:Alt+Insert => equals() and hashCode() => 選擇相應的參數
public class Demo17_HashSetExercise {public static void main(String[] args) {HashSet hashSet = new HashSet();hashSet.add(new Employee("jack", 18));hashSet.add(new Employee("mike", 28));hashSet.add(new Employee("jack", 18));System.out.println(hashSet);//[Employee{name='mike', age=28}, Employee{name='jack', age=18}]} } class Employee {String name;int age;@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Employee employee = (Employee) o;return age == employee.age && Objects.equals(name, employee.name);}@Overridepublic int hashCode() {return Objects.hash(name, age);}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public Employee(String name, int age) {this.name = name;this.age = age;}@Overridepublic String toString() {return "Employee{" +"name='" + name + '\'' +", age=" + age +'}';} }Set實現類–LinkedHashSet
基本介紹
- LinkedHashSet 是 HashSet的子類
- LinkedHashSet 底層是一個LinkedHashMap,底層維護了一個 數組 + 雙向鏈表
- LinkedHashSet 根據元素的 hashCode 值來決定元素的存儲位置,同時使用鏈表維護元素的次序,這使得元素看起來是以插入順序保存得。
- LinkedHashSet 不允許添加重復元素
說明:
源碼分析
public class Demo19_LinkedHashSet_Source {public static void main(String[] args) {LinkedHashSet set = new LinkedHashSet();set.add(new String("AA"));set.add(456);set.add(456);set.add(new Customer("劉",1001));set.add(123);set.add("kobe");for (int i = 0; i < 100; i++) {set.add(new Customer("kobe",24));}//也會樹化 parent、left、rightSystem.out.println(set);//1. LinkedHashSet 加入順序和遍歷順序一致//2. LinkedHashSet 底層是一個LinkedHashMap(是hashMap的子類)//3. LinkedHashSet 底層結構(數組table+雙向列表)//4. 添加第一次時,直接將數組table擴容到16,存放的結點類型 LinkedHashMap$Entry//5. 數組是HashMap$Node[] , 存放的元素/數據是 LinkedHashMap$Entry 類型/*//繼承關系是在內部類完成 , 都是靜態內部類static class Entry<K,V> extends HashMap.Node<K,V> {Entry<K,V> before, after;Entry(int hash, K key, V value, Node<K,V> next) {super(hash, key, value, next);}}*/} } class Customer{private String name;private int no;public Customer(String name, int no) {this.name = name;this.no = no;}@Overridepublic String toString() {return "Customer{" +"name='" + name + '\'' +", no=" + no +'}';}@Overridepublic int hashCode() {return 1;} }樹化后的結點結構
Set實現類–TreeSet
基本介紹
- 不允許添加重復元素,不允許添加 null,不允許添加
- 無序(沒有按照輸入順序進行輸出)
- 遍歷結果有順序
- 底層為排序二叉樹(紅黑樹),且采用中序遍歷得到結果 (左節點,根節點,右節點)
源碼分析
public class Demo_TreeSet {public static void main(String[] args) {//TreeSet treeSet = new TreeSet();//使用匿名內部類實現Comparator接口,并重寫compare方法,指定排序方法TreeSet treeSet = new TreeSet(new Comparator() {@Overridepublic int compare(Object o1, Object o2) {return ((String)o1).length() - ((String)o2).length();}});//添加數據treeSet.add("jack");treeSet.add("tom");treeSet.add("sp");treeSet.add("abc");//tom 和 abc 長度相等,key相等,添加失敗System.out.println(treeSet);//[sp, tom, jack]//1.當我們使用無參構造器時,創建TreeSet時,底層默認創建TreeMap/*public TreeSet() {this(new TreeMap<E,Object>());}*///TreeMap 如果使用默認構造函數,要求key是實現了Comparable接口的,并且使用key的compareTo方法比較,//也就是說仍然按照key排序,如果key沒有實現Comparable方法就會報錯/*String類實現了Comparable接口,重寫了compareTo方法:按升序排序,首字母先比較,相等再用第二個字母,以此類推public final class String implements java.io.Serializable, Comparable<String>, CharSequence {}*///2.上面的的代碼實現了添加元素按照字符串長度來排序//3./*public V put(K key, V value) {Entry<K,V> t = root;if (t == null) {compare(key, key); // type (and possibly null) checkroot = new Entry<>(key, value, null);size = 1;modCount++;return null;}int cmp;Entry<K,V> parent;// split comparator and comparable pathsComparator<? super K> cpr = comparator;//傳入的比較器if (cpr != null) {do {parent = t;cmp = cpr.compare(key, t.key);//動態綁定到我們的comparatorif (cmp < 0)t = t.left;else if (cmp > 0)t = t.right;elsereturn t.setValue(value);//如果比較器比較結果相同,更改value,不更改key//TreeSet的value是類,private static final Object PRESENT = new Object();} while (t != null);}else {//如果使用默認構造函數,即沒有比較器對象//要求key是實現了Comparable接口的,并且使用key的compareTo方法比較,if (key == null)//key不能為空throw new NullPointerException();@SuppressWarnings("unchecked")Comparable<? super K> k = (Comparable<? super K>) key;//要求key是實現了Comparable接口的do {parent = t;cmp = k.compareTo(t.key);//使用key的compareTo方法比較if (cmp < 0)t = t.left;else if (cmp > 0)t = t.right;elsereturn t.setValue(value);} while (t != null);}Entry<K,V> e = new Entry<>(key, value, parent);if (cmp < 0)parent.left = e;elseparent.right = e;fixAfterInsertion(e);//加入后紅黑樹旋轉size++;modCount++;return null;}*/treeSet = new TreeSet();treeSet.add(new C(1));treeSet.add(new C(2));treeSet.add(new C(1));System.out.println(treeSet);} } class C implements Comparable<C>{int num;public C(int num) {this.num = num;}public int compareTo( C c) {return this.num - c.num;}@Overridepublic String toString() {return "C{" +"num=" + num +'}';} }總結
以上是生活随笔為你收集整理的十 Java集合框架(2):Set接口的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: IDEA相关设置
- 下一篇: WEB前端学习笔记01利用纯CSS书写二