文章目錄
- 一、集合架構的概述
-
- 數組與集合
-
- 1.集合、數組都是對多個資料進行存儲操作的結構,簡稱 Java容器。
- 1.1 數組在存儲多個資料方面的特點:
- 1.2 數組在存儲多個資料方面的缺點:
- 集合存儲的優點
- 二、集合架構
-
- Collection接口方法
- Iterator 疊代器接口
-
- Iterator 接口的方法
-
- hasNext() , next()
- remove() 方法與foreach 循環周遊集合元素
- 代碼實作
- Collection 子接口之一:List 接口
-
- List接口概述:元素有序、且可重複
- List接口中的常用方法
-
- 總結:常用方法
- List實作類之一: ArrayList
-
- ArrayList的分析:
- 代碼實作
- List實作類之二: LinkedList
-
- LinkedList的分析:
- List實作類之三: Vector
- 面試題:ArrayList、LinkedList、Vector三者的異同?談談你的了解? ArrayList 底層是什麼?擴容機制? Vector 和 ArrayList 的最大差別
- Collection 子接口之二:Set 接口
-
- Set接口概述:存儲無序的、不可重複的資料
- Set實作類之一: HashSet
-
- 代碼實作
- Set實作類之二: LinkedHashSet
- Set實作類之三:TreeSet
- 周遊Collection的兩種方式
Arrays.asList (…) 方法傳回的 List 集合 既 不是 ArrayList 執行個體,也不是Vector 執行個體。 Arrays.asList (…) 傳回值是一個固定長度的 List 集合
一、集合架構的概述
數組與集合
1.集合、數組都是對多個資料進行存儲操作的結構,簡稱 Java容器。
說明:此時的存儲,主要指的是記憶體層面的存儲,不涉及到持久化的存儲(.txt,.jpg,.avi,資料庫中)
1.1 數組在存儲多個資料方面的特點:
- 一旦初始化以後,其長度就确定了。
-
數組一旦定義好,其元素的類型也就确定了。我們也就隻能操作指定類型的資料了。
比如:String[ ] arr ; int[ ] arr1 ; Object[ ] arr2;
1.2 數組在存儲多個資料方面的缺點:
- 一旦初始化以後,其長度就不可修改。
- 數組中提供的方法非常有限,對于添加、删除、插入資料等操作,非常不便,同時效率不高。
- 擷取數組中實際元素的個數的需求,數組沒有現成的屬性或方法可用
- 數組存儲資料的特點:有序、可重複。對于無序、不可重複的需求,不能滿足。
集合存儲的優點
解決數組存儲資料方面的弊端。
可以用于存儲數量不等的多個 對象 ,還可用于儲存具有映射關系的關聯數組
二、集合架構
Java集合可分為Collection和Map兩種體系
- Collection接口:單列集合,用來存儲一個一個的對象
- List接口:存儲有序的、可重複的資料。 -->“動态”數組
- ArrayList、LinkedList、Vector
- Set接口:存儲無序的、不可重複的資料 -->高中講的“集合”
- HashSet、LinkedHashSet、TreeSet
- List接口:存儲有序的、可重複的資料。 -->“動态”數組
Collection 接口繼承樹
- Map接口:雙列集合,用來存儲一對(key - value)一對的資料 -->高中函數:y = f(x)
- HashMap、LinkedHashMap、TreeMap、Hashtable、Properties
Collection接口方法
Collection coll = new ArrayList();
- 添加 add(Object obj) addAll(Collection coll)
//add(Object e):将元素e添加到集合coll中
coll.add("AA");
coll.add("BB");
coll.add(123);//自動裝箱
coll.add(new Date());
//addAll(Collection coll1):将coll1集合中的元素添加到目前的集合中
Collection coll1 = new ArrayList();
coll1.add(456);//自動裝箱
coll1.add("CC");
coll.addAll(coll1);
- 擷取有效元素的個數 int size()
//size():擷取添加的元素的個數
System.out.println(coll.size());//6
- 清空集合 void clear()
coll.clear();
- 是否是空集合 boolean isEmpty()
System.out.println(coll.isEmpty());
-
是否包含某個元素 contains containsAll
boolean contains(Object obj):是通過元素的equals方法來判斷是否是同一個對象
boolean containsAll(Collection c):也是調用元素的equals方法來比較的。拿兩個集合的元素挨個比較。
@Test
public void test1(){
Collection coll = new ArrayList();
coll.add(123);
coll.add(456);
coll.add(new Person("Jerry",20));//匿名對象
coll.add(new String("Tom"));
coll.add(false);
//1.contains(Object obj):判斷目前集合中是否包含obj
//我們在判斷時會調用obj對象所在類的equals()。
boolean contains = coll.contains(123);
System.out.println(contains);
System.out.println(coll.contains(new String("Tom")));
System.out.println(coll.contains(new Person("Jerry",20)));//true
//2.containsAll(Collection coll1):判斷形參coll1中的所有元素是否都存在于目前集合中。
Collection coll1 = Arrays.asList(123,4567);
System.out.println(coll.containsAll(coll1));
}
public class Person {
private String name;
private int age;
public Person(String name, int age) {this.name = name;this.age = age;}
public Person() { }
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;}
@Override
public boolean equals(Object o) {
System.out.println("這是重寫的equals");
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
if (age != person.age) return false;
return name != null ? name.equals(person.name) : person.name == null;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
-
删除 remove removeAll
boolean remove(Object obj) :通過元素的equals方法判斷是否是要删除的那個元素。隻會删除找到的第一個元素
collection.remove(1234);
boolean removeAll(Collection coll):取目前集合的差集
差集:從目前集合中移除collection1中所有的元素。
collection.removeAll(collection1);
-
取兩個集合的交集 retainAll
boolean retainAll(Collection c): 擷取目前集合和collection1集合的交集,并傳回給目前集合
- 集合是否相等 boolean equals(Object obj)
public void test3(){
Collection coll = new ArrayList();
coll.add(123);
coll.add(456);
coll.add(new Person("Jerry",20));
coll.add(new String("Tom"));
coll.add(false);
//7.retainAll(Collection coll1):交集:擷取目前集合和coll1集合的交集,并傳回給目前集合
Collection coll1 = Arrays.asList(123,456,789);
coll.retainAll(coll1);
System.out.println(coll);
//8.equals(Object obj):要想傳回true,需要目前集合和形參集合的元素都相同。
Collection coll1 = new ArrayList();
coll1.add(456);
coll1.add(123);
coll1.add(new Person("Jerry",20));
coll1.add(new String("Tom"));
coll1.add(false);
System.out.println(coll.equals(coll1));//false
}
- 轉成對象數組 Object[] toArray()
- 擷取集合對象的哈希值 hashCode()
- 周遊 iterator():傳回疊代器對象,用于集合周遊
public void test4(){
Collection coll = new ArrayList();
coll.add(123);
coll.add(456);
coll.add(new Person("Jerry",20));
coll.add(new String("Tom"));
coll.add(false);
//10.hashCode():傳回目前對象的哈希值
System.out.println(coll.hashCode());
//9.集合 --->數組:toArray()
Object[] arr = coll.toArray();
for(int i = 0;i < arr.length;i++){
System.out.println(arr[i]);
}
//拓展:數組 --->集合:調用Arrays類的靜态方法asList()
List<String> list = Arrays.asList(new String[]{"AA", "BB", "CC"});
System.out.println(list);
List arr1 = Arrays.asList(new int[]{123, 456});
System.out.println(arr1.size());//1
List arr2 = Arrays.asList(new Integer[]{123, 456});
System.out.println(arr2.size());//2
//9.iterator():傳回Iterator接口的執行個體,用于周遊集合元素。放在IteratorTest.java中測試
}
③ 普通的循環
Iterator 疊代器接口
概述
集合元素的周遊操作,使用疊代器Iterator接口
- Iterator 對象稱為疊代器 (設計模式的一種 ),主要用于周遊 Collection集合中的元素。
- GOF 給疊代器模式的定義為:提供一種方法通路一個容器 ( 對象中各個元素,而又不需暴露該對象的内部細節。 疊代器模式,就是為容器而生。 類似于“公共汽車上的售票員”、“火車上的乘務員”、 “空姐 。
- Collection 接口繼承了 java.lang.Iterable 接口,該接口有一個 iterator() 方法,那麼所有實作了 Collection 接口的集合類都有一個 iterator() 方法,用以傳回一個實作了Iterator 接口的對象 。
- Iterator 僅用于周遊集合 ,Iterator 本身并不提供承裝對象的能力。如果需要建立Iterator 對象,則必須有一個被疊代的集合。
Iterator 接口的方法
- 常用的内部的方法:hasNext() , next()和remove()
- 集合對象每次調用iterator()方法都得到一個全新的疊代器對象,預設遊标都在集合的第一個元素之前。
- 内部定義了remove(),可以在周遊的時候,删除集合中的元素。此方法不同于集合直接調用remove()
hasNext() , next()
public void test1(){
Collection coll = new ArrayList();
coll.add(123);coll.add(456);
coll.add(new Person("Jerry",20));
coll.add(new String("Tom"));
coll.add(false);
Iterator iterator = coll.iterator();
//方式一:
// System.out.println(iterator.next());
// System.out.println(iterator.next());
// System.out.println(iterator.next());
// System.out.println(iterator.next());
// System.out.println(iterator.next());
// //報異常:NoSuchElementException
// System.out.println(iterator.next());
//方式二:不推薦
// for(int i = 0;i < coll.size();i++)
// {System.out.println(iterator.next());}
//方式三:推薦
hasNext():判斷是否還有下一個元素
while(iterator.hasNext()){
//next():①指針下移 ②将下移以後集合位置上的元素傳回
System.out.println(iterator.next());
}
//錯誤方式一:
// Iterator iterator = coll.iterator();
// while((iterator.next()) != null){
// System.out.println(iterator.next());
// }
//錯誤方式二:
//集合對象每次調用iterator()方法都得到一個全新的疊代器對象,預設遊标都在集合的第一個元素之前。
// while (coll.iterator().hasNext()){
// System.out.println(coll.iterator().next());
}
}
remove() 方法與foreach 循環周遊集合元素
代碼實作
public void test3(){
Collection coll = new ArrayList();
coll.add(123);coll.add(456);
coll.add(new Person("Jerry",20));
coll.add(new String("Tom"));
coll.add(false);
//删除集合中"Tom"
Iterator iterator = coll.iterator();
while (iterator.hasNext()){
Object obj = iterator.next();
if("Tom".equals(obj))
iterator.remove();
}
//周遊集合
iterator = coll.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
//foreach周遊集合
for(Object obj : coll){
System.out.println(obj);
}
}
Collection 子接口之一:List 接口
List接口概述:元素有序、且可重複
- 鑒于 Java 中數組用來存儲資料 的局限性,我們通常使用 List 替代數組
- List 集合類中 元素有序、且可重複 ,集合中的每個元素都有其對應的順序索引。
- List 容器中的元素都對應一個整數型的序号記載其在容器中的位置,可以根據序号存取容器中的元素。
- JDK API 中 List 接口的實作類常用的有: ArrayList 、 LinkedList 和 Vector 。
- 添加的對象,所在的類要重寫equals()方法
- Collection接口:單列集合,用來存儲一個一個的對象
- List接口:存儲有序的、可重複的資料。 -->“動态”數組,替換原有的數組
- ArrayList:作為List接口的主要實作類;線程不安全的,效率高;底層使用Object[] elementData存儲
- LinkedList:對于頻繁的插入、删除操作,使用此類效率比ArrayList高;底層使用雙向連結清單存儲
- Vector:作為List接口的古老實作類;線程安全的,效率低;底層使用Object[] elementData存儲
- List接口:存儲有序的、可重複的資料。 -->“動态”數組,替換原有的數組
List接口中的常用方法
- List 除了從 Collection 集合繼承的方法外, List 集合裡添加了一些根據索引來操作集合元素的 方法 。
- void add(int index, Object ele):在index位置插入ele元素
- boolean addAll(int index, Collection eles):從index位置開始将eles中的所有元素添加進來
- Object get(int index):擷取指定index位置的元素
- int indexOf(Object obj):傳回obj在集合中首次出現的位置
- int lastIndexOf(Object obj):傳回obj在目前集合中末次出現的位置
- Object remove(int index):移除指定index位置的元素,并傳回此元素
- Object set(int index, Object ele):設定指定index位置的元素為ele
- List subList(int fromIndex, int toIndex):傳回從fromIndex到toIndex位置的子集合
總結:常用方法
增:add(Object obj)
删:remove(int index) / remove(Object obj)
改:set(int index, Object ele)
查:get(int index)
插:add(int index, Object ele)
長度:size()
周遊:① Iterator疊代器方式
② 增強for循環
List實作類之一: ArrayList
作為List接口的主要實作類;線程不安全的,效率高;底層使用Object[] elementData存儲
ArrayList的分析:
-
jdk 7情況下 像餓漢式,直接建立一個初始容量為 10 的數組
ArrayList list = new ArrayList();//底層建立了長度是10的Object[]數組elementData
list.add(123);//elementData[0] = new Integer(123);
…
list.add(11);//如果此次的添加導緻底層elementData數組容量不夠,則擴容。
預設情況下,擴容為原來的容量的1.5倍,同時需要将原有數組中的資料複制到新的數組中。
結論:建議開發中使用帶參的構造器:ArrayList list = new ArrayList(int capacity)
-
jdk 8中ArrayList的變化:ArrayList 像懶漢式,一開始建立一個長度為 0 的數組,當添加第一個元素時再建立一個始容量為 10 的 數組
ArrayList list = new ArrayList();//底層Object[] elementData初始化為{}.并沒有建立長度為10的數組
list.add(123);//第一次調用add()時,底層才建立了長度10的數組,并将資料123添加到elementData[0]
…
後續的添加和擴容操作與jdk 7 無異。
- 小結: jdk7中的ArrayList的對象的建立類似于單例的餓漢式,而jdk8中的ArrayList的對象的建立類似于單例的懶漢式,延遲了數組的建立,節省記憶體。
代碼實作
public void test1(){
ArrayList list = new ArrayList();
list.add(123);list.add(456);
list.add("AA");
list.add(new Person("Tom",12));
list.add(456);
System.out.println(list);//[123, 456, AA, Person{name='Tom', age=12}, 456]
//void add(int index, Object ele):在index位置插入ele元素
list.add(1,"BB");
System.out.println(list);//[123, BB, 456, AA, Person{name='Tom', age=12}, 456]
//boolean addAll(int index, Collection eles):從index位置開始将eles中的所有元素添加進來
List list1 = Arrays.asList(1, 2, 3);
list.addAll(list1);
//list.add(list1);
System.out.println(list.size());//9
//Object get(int index):擷取指定index位置的元素
System.out.println(list.get(0));//123
//int indexOf(Object obj):傳回obj在集合中首次出現的位置。如果不存在,傳回-1.
int index = list.indexOf(4567);
System.out.println(index);
//int lastIndexOf(Object obj):傳回obj在目前集合中末次出現的位置。如果不存在,傳回-1.
System.out.println(list.lastIndexOf(456));
//Object remove(int index):移除指定index位置的元素,并傳回此元素
Object obj = list.remove(0);
System.out.println(obj);
System.out.println(list);
//Object set(int index, Object ele):設定指定index位置的元素為ele
list.set(1,"CC");
System.out.println(list);
//List subList(int fromIndex, int toIndex):傳回從fromIndex到toIndex位置的左閉右開區間的子集合
List subList = list.subList(2, 4);
System.out.println(subList);
//疊代器:方式一Iterator疊代器方式
Iterator iterator = list.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
//方式二:增強for循環
for(Object obj : list){
System.out.println(obj);
}
//方式三:普通for循環
for(int i = 0;i < list.size();i++){
System.out.println(list.get(i));
}
}
List實作類之二: LinkedList
對于頻繁的插入、删除操作,使用此類效率比ArrayList高;底層使用 雙向連結清單 存儲
LinkedList的分析:
LinkedList list = new LinkedList();
内部沒有聲明數組,而是定義了 Node 類型的 first 和 last 用于記錄首末元素。同時,定義内部類,作為 LinkedList 中儲存資料的基
本結構。 Node 除了 儲存資料,還定義了兩個變量:
- prev 變量記錄前一個元素的位置
- next 變量記錄下一個元素的 位置
預設值為null
ist.add(123);//将123封裝到Node中,建立了Node對象。
其中,Node定義為:展現了LinkedList的雙向連結清單的說法
private 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;
}
}
新增方法
- void addFirst (Object obj
- void addLast (Object obj
- Object getFirst
- Object getLast
- Object removeFirst
- Object removeLast
List實作類之三: Vector
- Vector 是一個古老的集合, JDK1.0 就有了。大多數操作與 ArrayList相同,差別之處在于 Vector 是線程安全的。
-
在各種 list 中,最好把 ArrayList 作為預設選擇。當插入、删除頻繁時,
使用 LinkedList Vector 總是比 ArrayList 慢,是以盡量避免使用。
新增方法:
- void addElement (Object obj
- void insertElementAt (Object obj,int index)
- void setElementAt (Object obj,int index)
- void removeElement (Object obj
- void removeAllElements
Vector的源碼分析:jdk7和jdk8中通過Vector()構造器建立對象時,底層都建立了長度為10的數組。在擴容方面,預設擴容為原來的數組長度的2倍。
面試題:ArrayList、LinkedList、Vector三者的異同?談談你的了解? ArrayList 底層是什麼?擴容機制? Vector 和 ArrayList 的最大差別
同:
三個類都是實作了List接口,存儲資料的特點相同:存儲有序的、可重複的資料
不同:
ArrayList:作為List接口的主要實作類;線程不安全的,效率高;底層使用Object[] elementData存儲
LinkedList:線程不安全的,對于頻繁的插入、删除操作,使用此類效率比ArrayList高;底層使用雙向連結清單存儲
Vector:作為List接口的古老實作類;線程安全的,效率低;底層使用Object[] elementData存儲
-
ArrayList 和 LinkedList 的 異同
二者都線程不安全,相對線程安全的Vector ,執行效率高。
此外,ArrayList 是實作了基于動态數組的資料結構, LinkedList 基于連結清單的資料結構。對于随機通路 get 和 set ArrayList 覺得優于 LinkedList ,因為 LinkedList 要移動指針。對于新增和删除 操作 add( 特指 插入 和 remove LinkedList 比較占優勢,因為 ArrayList 要移動資料。
-
ArrayList 和 Vector 的差別
Vector和 ArrayList 幾乎是完全相同的 唯一的差別在于 Vector 是同步類 ( synchronized),屬于強同步類。是以開銷就比 ArrayList 要大,通路要慢。正常情況下 大多數的 Java 程式員使用ArrayList 而不是 Vector, 因為同步完全可以由程式員自己來控制。 Vector 每次擴容請求其大小的 2 倍空間,而 ArrayList 是 1.5 倍。 Vector 還有一個子類 Stack 。
Collection 子接口之二:Set 接口
Set接口概述:存儲無序的、不可重複的資料
Set接口的架構:
- Collection接口:單列集合,用來存儲一個一個的對象
- Set接口:存儲無序的、不可重複的資料 -->高中講的“集合”
- HashSet:作為Set接口的主要實作類;線程不安全的;可以存儲null值
-
LinkedHashSet:作為HashSet的子類;周遊其内部資料時,可以按照添加的順序周遊
對于頻繁的周遊操作,LinkedHashSet效率高于HashSet.
-
- TreeSet:可以按照添加對象的指定屬性,進行排序。
- HashSet:作為Set接口的主要實作類;線程不安全的;可以存儲null值
- Set接口:存儲無序的、不可重複的資料 -->高中講的“集合”
Set接口中沒有額外定義新的方法,使用的都是Collection中聲明過的方法。
要求:向Set(主要指:HashSet、LinkedHashSet)中添加的資料,其所在的類一定要重寫 hashCode() 和 equals()
要求:重寫的 hashCode() 和 equals() 盡可能保持一緻性:相等的對象必須具有相等的散列碼
(重寫兩個方法的小技巧:對象中用作 equals() 方法比較的 Field,都應該用來計算 hashCode 值。)
Set 集合不允許包含相同的元素,如果試把兩個相同的元素加入同一個Set 集合中,則添加操作失敗。
Set 判斷兩個對象是否相同不是使用 == 運算符,而是 根據 equals() 方法
- 一、Set:存儲無序的、不可重複的資料以HashSet為例說明
-
無序性:不等于随機性。存儲的資料在底層數組中并非按照數組索引的順序添加,而是根據資料的哈希值決定的。
不可重複性:保證添加的元素按照equals()判斷時,不能傳回true.即:相同的元素隻能添加一個。
二、添加元素的過程:以HashSet為例 -
我們向HashSet中添加元素a,首先調用元素a所在類的hashCode()方法,計算元素a的哈希值,
此哈希值接着通過某種算法計算出在HashSet底層數組中的存放位置(即為:索引位置),判斷數組此位置上是否已經有元素:
如果此位置上沒有其他元素,則元素a添加成功。 —>情況1
如果此位置上有其他元素b(或以連結清單形式存在的多個元素),則比較元素a與元素b的hash值:
如果hash值不相同,則元素a添加成功。—>情況2
如果hash值相同,進而需要調用元素a所在類的equals()方法:
equals()傳回true,元素a添加失敗
equals()傳回false,則元素a添加成功。—>情況3
對于添加成功的情況2和情況3而言:元素a 與已經存在指定索引位置上資料以連結清單的方式存儲。
jdk 7 :元素a放到數組中,指向原來的元素。
jdk 8 :原來的元素在數組中,指向元素a
總結: 7頭插,8尾插 七上八下
HashSet底層:數組+連結清單的結構。
Set實作類之一: HashSet
代碼實作
public void test1(){
Set set = new HashSet();
set.add(456);
set.add(123);
set.add(123);
set.add("AA");
set.add("CC");
set.add(new User("Tom",12));
set.add(new User("Tom",12));
set.add(129);
Iterator iterator = set.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
}
User
public class User implements Comparable{
private String name;
private int age;
public User() {}
public User(String name, int age) {this.name = name;this.age = 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;}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public boolean equals(Object o) {
System.out.println("User equals()....");
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
if (age != user.age) return false;
return name != null ? name.equals(user.name) : user.name == null;
}
@Override
public int hashCode() { //return name.hashCode() + age;
int result = name != null ? name.hashCode() : 0;
result = 31 * result + age;
return result;
}
}
Set實作類之二: LinkedHashSet
- LinkedHashSet 是 HashSet 的子類
-
LinkedHashSet 根據元素的 hashCode 值來決定元素的存儲位置,
但它 同時使用雙向連結清單 維護元素的次序,這使得元素看起來是以 插入順序儲存 的。
-
LinkedHashSet 插入性能略低于 HashSet 但在疊代通路 Set 裡的全
部元素時有很好的性能。
- LinkedHashSet 不允許集合元素重複。
- LinkedHashSet作為HashSet的子類,在添加資料的同時,每個資料還維護了兩個引用,記錄此資料前一個資料和後一個資料。
- 優點:對于頻繁的周遊操作,LinkedHashSet效率高于HashSet
Set實作類之三:TreeSet
- TreeSet 是 SortedSet 接口的實作類, TreeSet 可以確定集合元素處于排序 狀态。
- TreeSet 底層使用 紅黑樹 結構存儲資料
- 新增的方法如下: 了解
- Comparator comparator
- Object first()
- Object last()
- Object lower(Object e)
- Object higher(Object e)
- SortedSet subSet fromElement , toElement
- SortedSet headSet toElement
- SortedSet tailSet fromElement
- TreeSet 兩種排序方法: 自然排序 和 定制排序 。預設情況下, TreeSet 采用自然排序。
- 向TreeSet中添加的資料,要求是相同類的對象。因為隻有相同類的兩個執行個體才會比較大小,是以向 TreeSet 中添加的應該是同一個類 的 對象。
- 兩種排序方式:自然排序(實作Comparable接口) 和 定制排序(Comparator)
- 對于 TreeSet 集合而言,它 判斷兩個對象是否相等的唯一标準 是:兩個對象通過 compareTo (Object obj ) 方法比較 傳回 值。
- 自然排序中,比較兩個對象是否相同的标準為:compareTo()傳回0.不再是equals().
public void test1() {
TreeSet set = new TreeSet();
//失敗:不能添加不同類的對象
// set.add(123); set.add("AA");
set.add(new User("Tom", 12));
set.add(new User("Jerry", 32));
set.add(new User("Jim", 2));
set.add(new User("Mike", 65));
set.add(new User("Jack", 33));
set.add(new User("Jack", 56));
Iterator iterator = set.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
User
public class User implements Comparable{
private String name;
private int age;
public User() {
}
public User(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
//按照姓名從大到小排列,年齡從小到大排列
@Override
public int compareTo(Object o) {
if(o instanceof User){
User user = (User)o;
int compare = -this.name.compareTo(user.name);
if(compare != 0){
return compare;
}else{
return Integer.compare(this.age,user.age);
}
}else{
throw new RuntimeException("輸入的類型不比對");
}
}
}
- 定制排序中,比較兩個對象是否相同的标準為:compare()傳回0.不再是equals().
public void test2() {
Comparator com = new Comparator() {
//按照年齡從小到大排列
@Override
public int compare(Object o1, Object o2) {
if (o1 instanceof User && o2 instanceof User) {
User u1 = (User) o1;
User u2 = (User) o2;
return Integer.compare(u1.getAge(), u2.getAge());
} else {
throw new RuntimeException("輸入的資料類型不比對");
}
}
};
// 在有參數的情況下,按照參數的方式來
TreeSet set = new TreeSet(com);
set.add(new User("Tom", 12));
set.add(new User("Jerry", 32));
set.add(new User("Jim", 2));
set.add(new User("Mike", 65));
set.add(new User("Mary", 33));
set.add(new User("Jack", 33));
set.add(new User("Jack", 56));
Iterator iterator = set.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
周遊Collection的兩種方式
- 使用疊代器Iterator
- foreach循環(或增強for循環):
coll.forEach(System.out::println);//java8新特性,方法的引用