JAVA集合(笔记)
集合簡介
- 概念:對象的容器,定義了對多個對象進項操作的的常用方法??蓪崿F數組的功能。
- 和數組的區別:
- 位置: java.util.*;
Collection體系集合
Collection父接口
-
特點:代表一組任意類型的對象,無序、無下標、不能重復。
-
方法:
- boolean add(Object obj) //添加一個對象。
- boolean addAll(Collection c) //講一個集合中的所有對象添加到此集合中。
- void clear() //清空此集合中的所有對象。
- boolean contains(Object o) //檢查此集合中是否包含o對象。
- boolean equals(Object o) //比較此集合是否與指定對象相等。
- boolean isEmpty() //判斷此集合是否為空。
- boolean remove(Object o) //在此集合中移除o對象。
- int size() //返回此集合中的元素個數。
- Object[] toArray() //姜此集合轉換成數組。
Collection子接口
List集合
-
特點:有序、有下標、元素可以重復。
-
方法:
- void add(int index,Object o) //在index位置插入對象o。
- boolean addAll(index,Collection c) //將一個集合中的元素添加到此集合中的index位置。
- Object get(int index) //返回集合中指定位置的元素。
- List subList(int fromIndex,int toIndex) //返回fromIndex和toIndex之間的集合元素。
List實現類
ArrayList[重點]
- 數組結構實現,查詢塊、增刪慢;
- JDK1.2版本,運行效率快、線程不安全。
- [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-cqGEjbf9-1614751593954)(C:\Users\王東梁\AppData\Roaming\Typora\typora-user-images\image-20210228215642063.png)]
注:Object里的equals(this==obj)用地址和當前對象比較,如果想實現代碼中的問題,可以在學生類中重寫equals方法:
COPY@Override public boolean equals(Object obj) {//1.是否為同一對象if (this==obj) {return true;}//2.判斷是否為空if (obj==null) {return false;}//3.判斷是否是Student類型if (obj instanceof Student) {Student student=(Student) obj;//4.比較屬性if(this.name.equals(student.getName())&&this.age==student.age) {return true;}}//不滿足,返回falsereturn false; }ArrayList源碼分析
-
默認容量大小:private static final int DEFAULT_CAPACITY = 10;
-
存放元素的數組:transient Object[] elementData;
-
實際元素個數:private int size;
-
創建對象時調用的無參構造函數:
COPY//這是一個空的數組 private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; public ArrayList() {this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; }這段源碼說明當你沒有向集合中添加任何元素時,集合容量為0。那么默認的10個容量怎么來的呢?
這就得看看add方法的源碼了:
COPYpublic boolean add(E e) {ensureCapacityInternal(size + 1); // Increments modCount!!elementData[size++] = e;return true; }假設你new了一個數組,當前容量為0,size當然也為0。這時調用add方法進入到ensureCapacityInternal(size + 1);該方法源碼如下:
COPYprivate void ensureCapacityInternal(int minCapacity) {ensureExplicitCapacity(calculateCapacity(elementData, minCapacity)); }該方法中的參數minCapacity傳入的值為size+1也就是 1,接著我們再進入到calculateCapacity(elementData, minCapacity)里面:
COPYprivate static int calculateCapacity(Object[] elementData, int minCapacity) {if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {return Math.max(DEFAULT_CAPACITY, minCapacity);}return minCapacity; }上文說過,elementData就是存放元素的數組,當前容量為0,if條件成立,返回默認容量DEFAULT_CAPACITY也就是10。這個值作為參數又傳入ensureExplicitCapacity()方法中,進入該方法查看源碼:
COPYprivate void ensureExplicitCapacity(int minCapacity) {modCount++;// overflow-conscious codeif (minCapacity - elementData.length > 0)grow(minCapacity); }我們先不要管modCount這個變量。
因為elementData數組長度為0,所以if條件成立,調用grow方法,重要的部分來了,我們再次進入到grow方法的源碼中:
COPYprivate void grow(int minCapacity) {// overflow-conscious codeint oldCapacity = elementData.length;int newCapacity = oldCapacity + (oldCapacity >> 1);if (newCapacity - minCapacity < 0)newCapacity = minCapacity;if (newCapacity - MAX_ARRAY_SIZE > 0)newCapacity = hugeCapacity(minCapacity);// minCapacity is usually close to size, so this is a win:elementData = Arrays.copyOf(elementData, newCapacity); }這個方法先聲明了一個oldCapacity變量將數組長度賦給它,其值為0;又聲明了一個newCapacity變量其值為oldCapacity+一個增量,可以發現這個增量是和原數組長度有關的量,當然在這里也為0。第一個if條件滿足,newCapacity的值為10(這就是默認的容量,不理解的話再看看前面)。第二個if條件不成立,也可以不用注意,因為MAX_ARRAY_SIZE的定義如下:
COPYprivate static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;這個值太大了以至于第二個if條件沒有了解的必要。
最后一句話就是為elementData數組賦予了新的長度,Arrays.copyOf()方法返回的數組是新的數組對象,原數組對象不會改變,該拷貝不會影響原來的數組。copyOf()的第二個自變量指定要建立的新數組長度,如果新數組的長度超過原數組的長度,則保留數組默認值。
這時候再回到add的方法中,接著就向下執行elementData[size++] = e;到這里為止關于ArrayList就講解得差不多了,當數組長度為10的時候你們可以試著過一下源碼,查一下每次的增量是多少(答案是每次擴容為原來的1.5倍)。
Vector
-
數組結構實現,查詢快、增刪慢;
-
JDK1.0版本,運行效率慢、線程安全。
COPY/*** Vector的演示使用* *1.添加數據*2.刪除數據*3.遍歷*4.判斷*/ public class Demo1 {public static void main(String[] args) {Vector vector=new Vector<>();//1.添加數據vector.add("tang");vector.add("he");vector.add("yu");System.out.println("元素個數:"+vector.size());//2.刪除數據/** vector.remove(0); vector.remove("tang");*///3.遍歷//使用枚舉器Enumeration enumeration=vector.elements();while (enumeration.hasMoreElements()) {String s = (String) enumeration.nextElement();System.out.println(s);}//4.判斷System.out.println(vector.isEmpty());System.out.println(vector.contains("he"));//5. Vector其他方法//firstElement() lastElement() ElementAt();} }
LinkedList
- 鏈表結構實現,增刪快,查詢慢。
LinkedList源碼分析
LinkedList首先有三個屬性:
- 鏈表大小:transient int size = 0;
- (指向)第一個結點/頭結點:transient Node<E> first;
- (指向)最后一個結點/尾結點:transient Node<E> last;
關于Node類型我們再進入到類里看看:
COPYprivate static class Node<E> {E item;Node<E> next;Node<E> prev;Node(Node<E> prev, E element, Node<E> next) {this.item = element;this.next = next;this.prev = prev;} }首先item存放的是實際數據;next指向下一個結點而prev指向上一個結點。
Node帶參構造方法的三個參數分別是前一個結點、存儲的數據、后一個結點,調用這個構造方法時將它們賦值給當前對象。
LinkedList是如何添加元素的呢?先看看add方法:
COPYpublic boolean add(E e) {linkLast(e);return true; }進入到linkLast方法:
COPYvoid linkLast(E e) {final Node<E> l = last;final Node<E> newNode = new Node<>(l, e, null);last = newNode;if (l == null)first = newNode;elsel.next = newNode;size++;modCount++; }假設剛開始new了一個LinkedList對象,first和last屬性都為空,調用add進入到linkLast方法。
首先創建一個Node變量 l 將last(此時為空)賦給它,然后new一個newNode變量存儲數據,并且它的前驅指向l,后繼指向null;再把last指向newNode。如下圖所示:
如果滿足if條件,說明這是添加的第一個結點,將first指向newNode:
至此,LinkedList對象的第一個數據添加完畢。假設需要再添加一個數據,我們可以再來走一遍,過程同上不再贅述,圖示如下:
ArrayList和LinkedList區別
- ArrayList:必須開辟連續空間,查詢快,增刪慢。
- LinkedList:無需開辟連續空間,查詢慢,增刪快。
泛型概述
- Java泛型是JDK1.5中引入的一個新特性,其本質是參數化類型,把類型作為參數傳遞。
- 常見形式有泛型類、泛型接口、泛型方法。
- 語法:
- <T,…> T稱為類型占位符,表示一種引用類型。
- 好處:
- 提高代碼的重用性。
- 防止類型轉換異常,提高代碼的安全性。
泛型類
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-JNlbroFK-1614751593971)(C:\Users\王東梁\AppData\Roaming\Typora\typora-user-images\image-20210301155839838.png)]
COPY/*** 泛型類* 語法:類名<T>* T是類型占位符,表示一種引用類型,編寫多個使用逗號隔開* */ public class myGeneric<T>{//1.創建泛型變量//不能使用new來創建,因為泛型是不確定的類型,也可能擁有私密的構造方法。T t;//2.泛型作為方法的參數public void show(T t) {System.out.println(t);}//泛型作為方法的返回值public T getT() {return t;} } COPY/*** 注意:* 1.泛型只能使用引用類型* 2.不同泛型類型的對象不能相互賦值*/ public class testGeneric {public static void main(String[] args) {//使用泛型類創建對象myGeneric<String> myGeneric1=new myGeneric<String>();myGeneric1.t="tang";myGeneric1.show("he");myGeneric<Integer> myGeneric2=new myGeneric<Integer>();myGeneric2.t=10;myGeneric2.show(20);Integer integer=myGeneric2.getT();} }泛型接口
COPY/*** 泛型接口* 語法:接口名<T>* 注意:不能創建泛型靜態常量*/ public interface MyInterface<T> {//創建常量String nameString="tang";T server(T t); } COPY/*** 實現接口時確定泛型類*/ public class MyInterfaceImpl implements MyInterface<String>{@Overridepublic String server(String t) {System.out.println(t);return t; } } COPY//測試 MyInterfaceImpl myInterfaceImpl=new MyInterfaceImpl(); myInterfaceImpl.server("xxx"); //xxx COPY/*** 實現接口時不確定泛型類*/ public class MyInterfaceImpl2<T> implements MyInterface<T>{@Overridepublic T server(T t) {System.out.println(t);return t;} } COPY//測試 MyInterfaceImpl2<Integer> myInterfaceImpl2=new MyInterfaceImpl2<Integer>(); myInterfaceImpl2.server(2000); //2000泛型方法
COPY/*** 泛型方法* 語法:<T> 返回類型*/ public class MyGenericMethod {public <T> void show(T t) {System.out.println("泛型方法"+t);} } COPY//測試 MyGenericMethod myGenericMethod=new MyGenericMethod(); myGenericMethod.show("tang"); myGenericMethod.show(200); myGenericMethod.show(3.14);泛型集合
-
概念:參數化類型、類型安全的集合,強制集合元素的類型必須一致。
-
特點
:
- 編譯時即可檢查,而非運行時拋出異常。
- 訪問時,不必類型轉換(拆箱)。
- 不同泛型指尖引用不能相互賦值,泛型不存在多態。
之前我們在創建LinkedList類型對象的時候并沒有使用泛型,但是進到它的源碼中會發現:
COPYpublic class LinkedList<E>extends AbstractSequentialList<E>implements List<E>, Deque<E>, Cloneable, java.io.Serializable{//略}它是一個泛型類,而我之前使用的時候并沒有傳遞,說明java語法是允許的,這個時候傳遞的類型是Object類,雖然它是所有類的父類,可以存儲任意的類型,但是在遍歷、獲取元素時需要原來的類型就要進行強制轉換。這個時候就會出現一些問題,假如往鏈表里存儲了許多不同類型的數據,在強轉的時候就要判斷每一個原來的類型,這樣就很容易出現錯誤。
Set集合概述
Set子接口
- 特點:無序、無下標、元素不可重復。
- 方法:全部繼承自Collection中的方法。
Set實現類
HashSet【重點】
- 基于HashCode計算元素存放位置。
- 當存入元素的哈希碼相同時,會調用equals進行確認,如結果為true,則拒絕后者存入。
注:hashSet存儲過程:
存儲過程實際上就是重復依據,要實現“注”里的問題,可以重寫hashCode和equals代碼:
COPY@Override public int hashCode() {final int prime = 31;int result = 1;result = prime * result + age;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;Person other = (Person) obj;if (age != other.age)return false;if (name == null) {if (other.name != null)return false;} else if (!name.equals(other.name))return false;return true; }hashCode方法里為什么要使用31這個數字大概有兩個原因:
TreeSet
- 基于排序順序實現不重復。
- 實現了SortedSet接口,對集合元素自動排序。
- 元素對象的類型必須實現Comparable接口,指定排序規則。
- 通過CompareTo方法確定是否為重復元素。
查看Comparable接口的源碼,發現只有一個compareTo抽象方法,在人類中實現它:
COPYpublic class Person implements Comparable<Person>{@Override//1.先按姓名比//2.再按年齡比public int compareTo(Person o) {int n1=this.getName().compareTo(o.getName());int n2=this.age-o.getAge();return n1==0?n2:n1;} }除了實現Comparable接口里的比較方法,TreeSet也提供了一個帶比較器Comparator的構造方法,使用匿名內部類來實現它:
COPY/*** TreeSet的使用* Comparator:實現定制比較(比較器)*/ public class Demo5 {public static void main(String[] args) {TreeSet<Person> persons=new TreeSet<Person>(new Comparator<Person>() {@Overridepublic int compare(Person o1, Person o2) {// 先按年齡比較// 再按姓名比較int n1=o1.getAge()-o2.getAge();int n2=o1.getName().compareTo(o2.getName());return n1==0?n2:n1;} });Person p1=new Person("tang",21);Person p2=new Person("he", 22);Person p3=new Person("yu", 21);persons.add(p1);persons.add(p2);persons.add(p3);System.out.println(persons.toString());} }接下來我們來做一個小案例:
COPY/*** 要求:使用TreeSet集合實現字符串按照長度進行排序* helloworld tangrui hechengyang wangzixu yuguoming* Comparator接口實現定制比較*/ public class Demo6 {public static void main(String[] args) {TreeSet<String> treeSet=new TreeSet<String>(new Comparator<String>() {@Override//先比較字符串長度//再比較字符串public int compare(String o1, String o2) {int n1=o1.length()-o2.length();int n2=o1.compareTo(o2);return n1==0?n2:n1;} });treeSet.add("helloworld");treeSet.add("tangrui");treeSet.add("hechenyang");treeSet.add("yuguoming");treeSet.add("wangzixu");System.out.println(treeSet.toString());//輸出[tangrui, wangzixu, yuguoming, hechenyang, helloworld]} }Map集合概述
Map體系集合
-
Map接口的特點:
- 用于存儲任意鍵值對(Key-Value)。
- 鍵:無序、無下標、不允許重復(唯一)。
- 值:無序、無下標、允許重復。
-
特點:存儲一對數據(Key-Value),無序、無下標,鍵不可重復。
-
方法:
-
V put(K key,V value)//將對象存入到集合中,關聯鍵值。key重復則覆蓋原值。
-
Object get(Object key)//根據鍵獲取相應的值。
-
Set<K>//返回所有的key
-
Collection<V> values()//返回包含所有值的Collection集合。
-
Set<Map.Entry<K,V>>//鍵值匹配的set集合
-
Map集合的實現類
HashMap【重點】
-
JDK1.2版本,線程不安全,運行效率快;允許用null作為key或是value。
COPY/*** 學生類*/public class Student {private String name;private int id; public Student(String name, int id) {super();this.name = name;this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getId() {return id;}public void setId(int id) {this.id = id;}@Overridepublic String toString() {return "Student [name=" + name + ", age=" + id + "]";}} COPY/*** HashMap的使用* 存儲結構:哈希表(數組+鏈表+紅黑樹)*/public class Demo2 {public static void main(String[] args) {HashMap<Student, String> hashMap=new HashMap<Student, String>();Student s1=new Student("tang", 36);Student s2=new Student("yu", 101);Student s3=new Student("he", 10);//1.添加元素hashMap.put(s1, "成都");hashMap.put(s2, "杭州");hashMap.put(s3, "鄭州");//添加失敗,但會更新值hashMap.put(s3,"上海");//添加成功,不過兩個屬性一模一樣;//注:假如相同屬性便認為是同一個對象,怎么修改?hashMap.put(new Student("he", 10),"上海");System.out.println(hashMap.toString());//2.刪除元素hashMap.remove(s3);System.out.println(hashMap.toString());//3.遍歷//3.1 使用keySet()遍歷for (Student key : hashMap.keySet()) {System.out.println(key+" "+hashMap.get(key));}//3.2 使用entrySet()遍歷for (Entry<Student, String> entry : hashMap.entrySet()) {System.out.println(entry.getKey()+" "+entry.getValue());}//4.判斷//注:同上System.out.println(hashMap.containsKey(new Student("he", 10)));System.out.println(hashMap.containsValue("成都"));}}注:和之前說過的HashSet類似,重復依據是hashCode和equals方法,重寫即可:
COPY@Overridepublic int hashCode() {final int prime = 31;int result = 1;result = prime * result + id;result = prime * result + ((name == null) ? 0 : name.hashCode());return result;}@Overridepublic boolean equals(Object obj) {if (this == obj)return true;if (obj == null)return false;if (getClass() != obj.getClass())return false;Student other = (Student) obj;if (id != other.id)return false;if (name == null) {if (other.name != null)return false;} else if (!name.equals(other.name))return false;return true;}HashMap源碼分析
-
默認初始化容量:static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
- 數組最大容量:static final int MAXIMUM_CAPACITY = 1 << 30;
-
默認加載因子:static final float DEFAULT_LOAD_FACTOR = 0.75f;
-
鏈表調整為紅黑樹的鏈表長度閾值(JDK1.8):static final int TREEIFY_THRESHOLD = 8;
-
紅黑樹調整為鏈表的鏈表長度閾值(JDK1.8):static final int UNTREEIFY_THRESHOLD = 6;
-
鏈表調整為紅黑樹的數組最小閾值(JDK1.8):static final int MIN_TREEIFY_CAPACITY = 64;
-
HashMap存儲的數組:transient Node<K,V>[] table;
-
HashMap存儲的元素個數:transient int size;
- 默認加載因子是什么?
- 就是判斷數組是否擴容的一個因子。假如數組容量為100,如果HashMap的存儲元素個數超過了100*0.75=75,那么就會進行擴容。
- 鏈表調整為紅黑樹的鏈表長度閾值是什么?
- 假設在數組中下標為3的位置已經存儲了數據,當新增數據時通過哈希碼得到的存儲位置又是3,那么就會在該位置形成一個鏈表,當鏈表過長時就會轉換成紅黑樹以提高執行效率,這個閾值就是鏈表轉換成紅黑樹的最短鏈表長度;
- 紅黑樹調整為鏈表的鏈表長度閾值是什么?
- 當紅黑樹的元素個數小于該閾值時就會轉換成鏈表。
- 鏈表調整為紅黑樹的數組最小閾值是什么?
- 并不是只要鏈表長度大于8就可以轉換成紅黑樹,在前者條件成立的情況下,數組的容量必須大于等于64才會進行轉換。
HashMap的數組table存儲的就是一個個的Node<K,V>類型,很清晰地看到有一對鍵值,還有一個指向next的指針(以下只截取了部分源碼):
COPYstatic class Node<K,V> implements Map.Entry<K,V> {final K key;V value;Node<K,V> next;}之前的代碼中在new對象時調用的是HashMap的無參構造方法,進入到該構造方法的源碼查看一下:
COPYpublic HashMap() {this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted}發現沒什么內容,只是賦值了一個默認加載因子;而在上文我們觀察到源碼中table和size都沒有賦予初始值,說明剛創建的HashMap對象沒有分配容量,并不擁有默認的16個空間大小,這樣做的目的是為了節約空間,此時table為null,size為0。
當我們往對象里添加元素時調用put方法:
COPYpublic V put(K key, V value) {return putVal(hash(key), key, value, false, true);}put方法把key和value傳給了putVal,同時還傳入了一個hash(Key)所返回的值,這是一個產生哈希值的方法,再進入到putVal方法(部分源碼):
COPYfinal V putVal(int hash, K key, V value, boolean onlyIfAbsent,boolean evict) {Node<K,V>[] tab; Node<K,V> p; int n, i;if ((tab = table) == null || (n = tab.length) == 0)n = (tab = resize()).length;if ((p = tab[i = (n - 1) & hash]) == null)tab[i] = newNode(hash, key, value, null);else{//略}}這里面創建了一個tab數組和一個Node變量p,第一個if實際是判斷table是否為空,而我們現在只關注剛創建HashMap對象時的狀態,此時tab和table都為空,滿足條件,執行內部代碼,這條代碼其實就是把resize()所返回的結果賦給tab,n就是tab的長度,resize顧名思義就是重新調整大小。查看resize()源碼(部分):
COPYfinal Node<K,V>[] resize() {Node<K,V>[] oldTab = table;int oldCap = (oldTab == null) ? 0 : oldTab.length;int oldThr = threshold;if (oldCap > 0);else if (oldThr > 0);else { // zero initial threshold signifies using defaultsnewCap = DEFAULT_INITIAL_CAPACITY;newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);} @SuppressWarnings({"rawtypes","unchecked"})Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];table = newTab;return newTab;}該方法首先把table及其長度賦值給oldTab和oldCap;threshold是閾值的意思,此時為0,所以前兩個if先不管,最后else里newCap的值為默認初始化容量16;往下創建了一個newCap大小的數組并將其賦給了table,剛創建的HashMap對象就在這里獲得了初始容量。然后我們再回到putVal方法,第二個if就是根據哈希碼得到的tab中的一個位置是否為空,為空便直接添加元素,此時數組中無元素所以直接添加。至此HashMap對象就完成了第一個元素的添加。當添加的元素超過16*0.75=12時,就會進行擴容:
COPYfinal V putVal(int hash, K key, V value, boolean onlyIfAbsent,boolean evict){if (++size > threshold)resize();}擴容的代碼如下(部分):
COPYfinal Node<K,V>[] resize() {int oldCap = (oldTab == null) ? 0 : oldTab.length;int newCap;if (oldCap > 0) {if (oldCap >= MAXIMUM_CAPACITY) {//略}else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&oldCap >= DEFAULT_INITIAL_CAPACITY)}}核心部分是else if里的移位操作,也就是說每次擴容都是原來大小的兩倍。
- 默認加載因子是什么?
-
注*:額外說明的一點是在JDK1.8以前鏈表是頭插入,JDK1.8以后鏈表是尾插入。
HashSet源碼分析
了解完HashMap之后,再回過頭來看之前的HashSet源碼,為什么放在后面寫你們看一下源碼就知道了(部分):
COPYpublic class HashSet<E>extends AbstractSet<E>implements Set<E>, Cloneable, java.io.Serializable{private transient HashMap<E,Object> map;private static final Object PRESENT = new Object();public HashSet() {map = new HashMap<>();}}可以看見HashSet的存儲結構就是HashMap,那它的存儲方式是怎樣的呢?可以看一下add方法:
COPYpublic boolean add(E e) {return map.put(e, PRESENT)==null;}很明了地發現它的add方法調用的就是map的put方法,把元素作為map的key傳進去的。。
Hashtable
-
JDK1.0版本,線程安全,運行效率慢;不允許null作為key或是value。
-
初始容量11,加載因子0.75。
這個集合在開發過程中已經不用了,稍微了解即可。
Properties
- Hashtable的子類,要求key和value都是String。通常用于配置文件的讀取。
它繼承了Hashtable的方法,與流關系密切,此處不詳解。
TreeMap
- 實現了SortedMap接口(是Map的子接口),可以對key自動排序。
在學生類中實現Comparable接口:
COPYpublic class Student implements Comparable<Student>{@Overridepublic int compareTo(Student o) {int n1=this.id-o.id;return n1; }除此之外還可以使用比較器來定制比較:
COPYTreeMap<Student, Integer> treeMap2=new TreeMap<Student, Integer>(new Comparator<Student>() {@Overridepublic int compare(Student o1, Student o2) {// 略return 0;} });TreeSet源碼
和HashSet類似,放在TreeMap之后講便一目了然(部分):
COPYpublic class TreeSet<E> extends AbstractSet<E>implements NavigableSet<E>, Cloneable, java.io.Serializable {private transient NavigableMap<E,Object> m;private static final Object PRESENT = new Object();TreeSet(NavigableMap<E,Object> m) {this.m = m;}public TreeSet() {this(new TreeMap<E,Object>());} }TreeSet的存儲結構實際上就是TreeMap,再來看其存儲方式:
COPYpublic boolean add(E e) {return m.put(e, PRESENT)==null; }它的add方法調用的就是TreeMap的put方法,將元素作為key傳入到存儲結構中。
Collections工具類
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-iJZH8Shy-1614751593973)(C:\Users\王東梁\AppData\Roaming\Typora\typora-user-images\image-20210303135614014.png)]
-
概念:集合工具類,定義了除了存取以外的集合常用方法。
-
方法:
- public static void reverse(List<?> list)//反轉集合中元素的順序
- public static void shuffle(List<?> list)//隨機重置集合元素的順序
- public static void sort(List<T> list)//升序排序(元素類型必須實現Comparable接口)
總結
以上是生活随笔為你收集整理的JAVA集合(笔记)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: GoDaddy vs.谷歌云平台-受欢迎
- 下一篇: 字符VS字节