3.3 集合
- 一方面, 面向?qū)ο笳Z(yǔ)言對(duì)事物的體現(xiàn)都是以對(duì)象的形式,為了方便對(duì)多個(gè)對(duì)象的操作,就要對(duì)對(duì)象進(jìn)行存儲(chǔ)。另一方面,使用Array存儲(chǔ)對(duì)象方面具有一些弊端,而Java 集合就像一種容器,可以動(dòng)態(tài)地把多個(gè)對(duì)象的引用放入容器中。
- Java 集合類可以用于存儲(chǔ)數(shù)量不等的多個(gè)對(duì)象,還可用于保存具有映射關(guān)系的關(guān)聯(lián)數(shù)組。
Java 集合可分為 Collection 和 Map 兩種體系
- Collection接口:
- Set:元素?zé)o序、不可重復(fù)的集合 ---類似高中的“集合”
- List:元素有序,可重復(fù)的集合 ---”動(dòng)態(tài)”數(shù)組
- Map接口:具有映射關(guān)系“key-value對(duì)”的集合 ---類似于高中的“函數(shù)” y = f(x) (x1,y1) (x2,y2)
3.3.1 Collection接口
- Collection 接口是 List、Set 和 Queue 接口的父接口,該接口里定義的方法既可用于操作 Set 集合,也可用于操作 List 和 Queue 集合。
- JDK不提供此接口的任何直接實(shí)現(xiàn),而是提供更具體的子接口(如:Set和List)實(shí)現(xiàn)。
- 在 Java5 之前,Java 集合會(huì)丟失容器中所有對(duì)象的數(shù)據(jù)類型,把所有對(duì)象都當(dāng)成 Object 類型處理;從 Java5 增加了泛型以后,Java 集合可以記住容器中對(duì)象的數(shù)據(jù)類型
Collection接口繼承樹(shù)

集合中數(shù)組間轉(zhuǎn)換操作:
方法類型 | 方法 |
---|---|
Object[] | toArray() 返回包含此collection中所有元素的數(shù)組 |
<T> T[] | toArray(T[] a) 返回包含此 collection中所有元素的數(shù)組;返回?cái)?shù)組的運(yùn)行時(shí)類型與指定數(shù)組的運(yùn)行時(shí)類型相同 |
3.3.1.1 Iterator接口
- Iterator對(duì)象稱為迭代器(設(shè)計(jì)模式的一種),主要用于遍歷 Collection 集合中的元素。
- 所有實(shí)現(xiàn)了Collection接口的集合類都有一個(gè)iterator()方法,用以返回一個(gè)實(shí)現(xiàn)了Iterator接口的對(duì)象。
- Iterator 僅用于遍歷集合,Iterator 本身并不提供承裝對(duì)象的能力。如果需要?jiǎng)?chuàng)建 Iterator 對(duì)象,則必須有一個(gè)被迭代的集合。
Iterator接口方法:

在調(diào)用iterator.next()方法之前必須要調(diào)用iterator.hasNext()進(jìn)行檢測(cè)。
若不調(diào)用,且下一條記錄無(wú)效,直接調(diào)用iterator.next()會(huì)拋出NoSuchElementException異常。
//List的知識(shí)將在下面講到。這里先做演示
List l=new ArrayList();
//因?yàn)镃ollection framework只能存儲(chǔ)對(duì)象所以new封裝類
l.add(new Integer(1));
l.add(new Integer(2));
l.add(new Integer(3));
l.add(new Integer(4));
Iterator x = l.iterator();
while(x.hasNext()){
Object o = x.next();
System.out.println(o);
}
輸出結(jié)果:
1
2
3
4
java5中提供了foreach循環(huán)迭代訪問(wèn)Collection
代碼示例
class Persons{
public String name ;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
Persons(){
}
Persons(String name){
this.name = name;
}
public static void main(String[] args) {
List<Persons> persons = new ArrayList<Persons>();
persons.add(new Persons("張三"));
persons.add(new Persons("李四"));
persons.add(new Persons("王五"));
persons.add(new Persons("趙六"));
for(Persons person: persons){
System.out.println(person.getName());
}
//其中:
//Persons 代表要遍歷的元素類型
//person 代表遍歷后元素名稱
//persons 代表要遍歷的元素名稱
}
}
輸出結(jié)果:
張三
李四
王五
趙六
3.3.1.2 List接口
- Java中數(shù)組用來(lái)存儲(chǔ)數(shù)據(jù)的局限性
- List集合類中元素有序、且可重復(fù),集合中的每個(gè)元素都有其對(duì)應(yīng)的順序索引。
- List容器中的元素都對(duì)應(yīng)一個(gè)整數(shù)型的序號(hào)記載其在容器中的位置,可以根據(jù)序號(hào)存取容器中的元素。
- JDK API中List接口的實(shí)現(xiàn)類常用的有:ArrayList、LinkedList和Vector。
- List 集合里添加了一些根據(jù)索引來(lái)操作集合元素的方法
- void add(int index, Object ele)
- boolean addAll(int index, Collection eles)
- Object get(int index)
- int indexOf(Object obj)
- int lastIndexOf(Object obj)
- Object remove(int index)
- Object set(int index, Object ele)
- List subList(int fromIndex, int toIndex)
ArrayList
- ArrayList 是 List 接口的典型實(shí)現(xiàn)類
- 本質(zhì)上,ArrayList是對(duì)象引用的一個(gè)變長(zhǎng)數(shù)組
- ArrayList 是線程不安全的,而 Vector 是線程安全的,即使為保證 List 集合線程安全,也不推薦使用Vector
- Arrays.asList(…) 方法返回的 List 集合既不是 ArrayList 實(shí)例,也不是 Vector 實(shí)例。Arrays.asList(…) 返回值是一個(gè)固定長(zhǎng)度的 List 集合
LinkedList
對(duì)于頻繁的插入或刪除元素的操作,建議使用LinkedList類,效率較高
-
新增方法:
void addFirst(Object obj) void addLast(Object obj) Object getFirst() Object getLast() Object removeFirst() Object removeLast()
代碼示例
// List 接口的鏈接列表實(shí)現(xiàn)
LinkedList<String> list = new LinkedList<String>();
list.push("one");
list.push("two");
list.push("three");
list.push("four");
Iterator<String> lit = list.iterator();
while (lit.hasNext()) {
System.out.println(list.pop());
}
System.out.println(list.size() + "---------");
輸出結(jié)果:
four
three
two
one
0---------
Vector
Vector 是一個(gè)古老的集合,JDK1.0就有了。大多數(shù)操作與ArrayList相同,區(qū)別之處在于Vector是線程安全的。
在各種list中,最好把ArrayList作為缺省選擇。當(dāng)插入、刪除頻繁時(shí),使用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<String> v = new Vector<String>();// 10
// 同步
v.add("one");
v.add("two");
v.add("three");
v.add("one");
v.add("two");
v.add("three");
for (int i = 0; i < v.size(); i++) {
System.out.print(v.get(i)+" ");
}
System.out.println("v.size() = "+v.size());
System.out.println("使用insertElementAt方法");
v.insertElementAt("啊哈", 0);
for (int i = 0; i < v.size(); i++) {
System.out.print(v.get(i)+" ");
}
System.out.println("v.size() = "+v.size());
System.out.println("使用remove方法");
v.remove(0);
for (int i = 0; i < v.size(); i++) {
System.out.print(v.get(i)+" ");
}
System.out.println("v.size() = "+v.size());
System.out.println("使用removeAllElements方法");
v.removeAllElements();
for (int i = 0; i < v.size(); i++) {
System.out.print(v.get(i)+" ");
}
System.out.println("v.size() = "+v.size());
輸出結(jié)果:
one two three one two three v.size() = 6
使用insertElementAt方法
啊哈 one two three one two three v.size() = 7
使用remove方法
one two three one two three v.size() = 6
使用removeAllElements方法
v.size() = 0
LinkedList、ArrayList和Vector區(qū)別
1.ArrayList是最常用的List實(shí)現(xiàn)類,內(nèi)部是通過(guò)數(shù)組實(shí)現(xiàn)的,它允許對(duì)元素進(jìn)行快速隨機(jī)訪問(wèn)。數(shù)組的缺點(diǎn)是每個(gè)元素之間不能有間隔,當(dāng)數(shù)組大小不滿足時(shí)需要增加存儲(chǔ)能力,就要講已經(jīng)有數(shù)組的數(shù)據(jù)復(fù)制到新的存儲(chǔ)空間中。當(dāng)從ArrayList的中間位置插入或者刪除元素時(shí),需要對(duì)數(shù)組進(jìn)行復(fù)制、移動(dòng)、代價(jià)比較高。因此,它適合隨機(jī)查找和遍歷,不適合插入和刪除。
2.Vector與ArrayList一樣,也是通過(guò)數(shù)組實(shí)現(xiàn)的,不同的是它支持線程的同步,即某一時(shí)刻只有一個(gè)線程能夠?qū)慥ector,避免多線程同時(shí)寫(xiě)而引起的不一致性,但實(shí)現(xiàn)同步需要很高的花費(fèi),因此,訪問(wèn)它比訪問(wèn)ArrayList慢。
3.LinkedList是用鏈表結(jié)構(gòu)存儲(chǔ)數(shù)據(jù)的,很適合數(shù)據(jù)的動(dòng)態(tài)插入和刪除,隨機(jī)訪問(wèn)和遍歷速度比較慢。另外,他還提供了List接口中沒(méi)有定義的方法,專門(mén)用于操作表頭和表尾元素,可以當(dāng)作堆棧、隊(duì)列和雙向隊(duì)列使用。
ArrayList和Vector的區(qū)別。
一.同步性:Vector是線程安全的,也就是說(shuō)是同步的,而ArrayList是線程序不安全的,不是同步的
二.數(shù)據(jù)增長(zhǎng):當(dāng)需要增長(zhǎng)時(shí),Vector默認(rèn)增長(zhǎng)為原來(lái)一培,而ArrayList卻是原來(lái)的一半
ArrayList 默認(rèn)量:0 -10 增量 原來(lái)一半
Vector 默認(rèn)量: 10 增量 原來(lái)的一倍。
拓展了解:ListIterator接口
- List 額外提供了一個(gè) listIterator() 方法,該方法返回一個(gè) ListIterator 對(duì)象, ListIterator 接口繼承了 Iterator 接口,提供了專門(mén)操作 List 的方法:
- void add()
- boolean hasPrevious()
- Object previous()
- Boolean hasNext()
- Object next()
Iterator和ListIterator主要區(qū)別
一、ListIterator和Iterator都有hasNext()和next()方法,可以實(shí)現(xiàn)順序向后遍歷。但是ListIterator有hasPrevious()和previous()方法,可以實(shí)現(xiàn)逆向(順序向前)遍歷。Iterator就不可以。
二、ListIterator可以定位當(dāng)前的索引位置,nextIndex()和previousIndex()可以實(shí)現(xiàn)。Iterator 沒(méi)有此功能。
三、ListIterator有add()方法,可以向List中插入對(duì)象,而Iterator不能。
四、都可實(shí)現(xiàn)刪除對(duì)象,但是ListIterator可以實(shí)現(xiàn)對(duì)象的修改,set()方法可以實(shí)現(xiàn)。Iterator僅能遍歷,不能修改。因?yàn)長(zhǎng)istIterator的這些功能,可以實(shí)現(xiàn)對(duì)LinkedList等List數(shù)據(jù)結(jié)構(gòu)的操作。
3.3.1.3 Set接口
- Set接口是Collection的子接口,set接口沒(méi)有提供額外的方法
- Set 集合不允許包含相同的元素,如果試把兩個(gè)相同的元素加入同一個(gè) Set 集合中,則添加操作失敗。
- Set 判斷兩個(gè)對(duì)象是否相同不是使用 == 運(yùn)算符,而是根據(jù) equals 方法
Set實(shí)現(xiàn)類之一 HashSet
- HashSet 是 Set 接口的典型實(shí)現(xiàn),大多數(shù)時(shí)候使用 Set 集合時(shí)都使用這個(gè)實(shí)現(xiàn)類。
- HashSet 按 Hash 算法來(lái)存儲(chǔ)集合中的元素,因此具有很好的存取和查找性能。
- HashSet 具有以下特點(diǎn):
- 不能保證元素的排列順序
- HashSet 不是線程安全的
- 集合元素可以是 null
- 當(dāng)向 HashSet 集合中存入一個(gè)元素時(shí),HashSet 會(huì)調(diào)用該對(duì)象的 hashCode() 方法來(lái)得到該對(duì)象的 hashCode 值,然后根據(jù) hashCode 值決定該對(duì)象在 HashSet 中的存儲(chǔ)位置。
- HashSet 集合判斷兩個(gè)元素相等的標(biāo)準(zhǔn):兩個(gè)對(duì)象通過(guò) hashCode() 方法比較相等,并且兩個(gè)對(duì)象的 equals() 方法返回值也相等。
代碼示例
Set<String> set = new HashSet<String>();// ctrl+shift+O
set.add("one");
set.add("one");
set.add("two");
set.add("three");
set.add("four");
/*
* for(int i=0;i<set.size();i++){ set. }
*/
System.out.println("長(zhǎng)度:" + set.size());
Iterator<String> it = set.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
輸出結(jié)果:
長(zhǎng)度:4
four
one
two
three
HashCode()
- 如果兩個(gè)元素的 equals() 方法返回 true,但它們的 hashCode() 返回值不相等,hashSet 將會(huì)把它們存儲(chǔ)在不同的位置,但依然可以添加成功。
- 對(duì)于存放在Set容器中的對(duì)象,對(duì)應(yīng)的類一定要重寫(xiě)equals()和hashCode(Object obj)方法,以實(shí)現(xiàn)對(duì)象相等規(guī)則。
- 重寫(xiě) hashCode() 方法的基本原則:
- 在程序運(yùn)行時(shí),同一個(gè)對(duì)象多次調(diào)用 hashCode() 方法應(yīng)該返回相同的值
- 當(dāng)兩個(gè)對(duì)象的 equals() 方法比較返回 true 時(shí),這兩個(gè)對(duì)象的 hashCode() 方法的返回值也應(yīng)相等
- 對(duì)象中用作 equals() 方法比較的 Field,都應(yīng)該用來(lái)計(jì)算 hashCode 值
Set實(shí)現(xiàn)類之二 LinkedHashSet
- LinkedHashSet 是 HashSet 的子類
- LinkedHashSet 根據(jù)元素的 hashCode 值來(lái)決定元素的存儲(chǔ)位置,但它同時(shí)使用鏈表維護(hù)元素的次序,這使得元素看起來(lái)是以插入順序保存的。
- LinkedHashSet插入性能略低于 HashSet,但在迭代訪問(wèn) Set 里的全部元素時(shí)有很好的性能。
- LinkedHashSet 不允許集合元素重復(fù)。
代碼示例
Set<String> set = new LinkedHashSet<String>();// ctrl+shift+O
set.add("one");
set.add("two");
set.add("three");
set.add("four");
set.add("four");
/*
* for(int i=0;i<set.size();i++){ set. }
*/
System.out.println("長(zhǎng)度:" + set.size());
Iterator<String> it = set.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
輸出結(jié)果:
長(zhǎng)度:4
one
four
two
three
Set實(shí)現(xiàn)類之三 TreeSet
- TreeSet 是 SortedSet 接口的實(shí)現(xiàn)類,TreeSet 可以確保集合元素處于排序狀態(tài)。
- 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 兩種排序方法:自然排序和定制排序。默認(rèn)情況下,TreeSet 采用自然排序。
案例5
public static void main(String[] args) {
//創(chuàng)建對(duì)象
TreeSet<String> set = new TreeSet<String>();
//添加數(shù)據(jù)
set.add("f");
set.add("y");
set.add("A");
set.add("Z");
System.out.println("長(zhǎng)度 "+set.size());
System.out.println("第一個(gè)元素:"+set.first());
System.out.println("最后個(gè)元素:"+set.last());
System.out.println("--------------------");
Iterator<String> it = set.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
輸出結(jié)果:
長(zhǎng)度 4
第一個(gè)元素:A
最后個(gè)元素:y
--------------------
A
Z
f
y
自然排序
- 自然排序:TreeSet 會(huì)調(diào)用集合元素的 compareTo(Object obj) 方法來(lái)比較元素之間的大小關(guān)系,然后將集合元素按升序排列
- 如果試圖把一個(gè)對(duì)象添加到 TreeSet 時(shí),則該對(duì)象的類必須實(shí)現(xiàn) Comparable 接口。
- 實(shí)現(xiàn) Comparable 的類必須實(shí)現(xiàn) compareTo(Object obj) 方法,兩個(gè)對(duì)象即通過(guò) compareTo(Object obj) 方法的返回值來(lái)比較大小。
- Comparable 的典型實(shí)現(xiàn):
- BigDecimal、BigInteger 以及所有的數(shù)值型對(duì)應(yīng)的包裝類:按它們對(duì)應(yīng)的數(shù)值大小進(jìn)行比較
- Character:按字符的 unicode值來(lái)進(jìn)行比較
- Boolean:true 對(duì)應(yīng)的包裝類實(shí)例大于 false 對(duì)應(yīng)的包裝類實(shí)例
- String:按字符串中字符的 unicode 值進(jìn)行比較
- Date、Time:后邊的時(shí)間、日期比前面的時(shí)間、日期大
- 向 TreeSet 中添加元素時(shí),只有第一個(gè)元素?zé)o須比較compareTo()方法,后面添加的所有元素都會(huì)調(diào)用compareTo()方法進(jìn)行比較。
- 因?yàn)橹挥邢嗤惖膬蓚€(gè)實(shí)例才會(huì)比較大小,所以向 TreeSet 中添加的應(yīng)該是同一個(gè)類的對(duì)象
- 對(duì)于 TreeSet 集合而言,它判斷兩個(gè)對(duì)象是否相等的唯一標(biāo)準(zhǔn)是:兩個(gè)對(duì)象通過(guò) compareTo(Object obj) 方法比較返回值
- 當(dāng)需要把一個(gè)對(duì)象放入 TreeSet 中,重寫(xiě)該對(duì)象對(duì)應(yīng)的 equals() 方法時(shí),應(yīng)保證該方法與 compareTo(Object obj) 方法有一致的結(jié)果:如果兩個(gè)對(duì)象通過(guò) equals() 方法比較返回 true,則通過(guò) compareTo(Object obj) 方法比較應(yīng)返回 0
定制排序
- TreeSet的自然排序是根據(jù)集合元素的大小,進(jìn)行元素升序排列。如果需要定制排序,比如降序排列,可通過(guò)Comparator接口的幫助。需要重寫(xiě)compare(T o1,T o2)方法。
- 利用int compare(T o1,T o2)方法,比較o1和o2的大小:如果方法返回正整數(shù),則表示o1大于o2;如果返回0,表示相等;返回負(fù)整數(shù),表示o1小于o2。
- 要實(shí)現(xiàn)定制排序,需要將實(shí)現(xiàn)Comparator接口的實(shí)例作為形參傳遞給TreeSet的構(gòu)造器。
- 此時(shí),仍然只能向TreeSet中添加類型相同的對(duì)象。否則發(fā)生ClassCastException異常。
- 使用定制排序判斷兩個(gè)元素相等的標(biāo)準(zhǔn)是:通過(guò)Comparator比較兩個(gè)元素返回了0。
Set和List區(qū)別
- Set中的元素不能重復(fù)
- 類似數(shù)學(xué)中集合的概念,元素是唯一的
- 怎么叫做重復(fù)?
- List中的元素允許重復(fù)
- 隱含地有個(gè)順序關(guān)系
- 支持ListIterator迭代器,能回溯
集合的能力:
并集
boolean addAll(Collection collectionToAdd)
差集
boolean removeAll(Collection collectionToAdd)
交集
boolean retainAll(Collection collectionToAdd)
代碼示例
public static void main(String[] args) {
Set set1=new HashSet();
set1.add(new Date()); //向列表中添加數(shù)據(jù)
set1.add("apple"); //向列表中添加數(shù)據(jù)
set1.add(new Integer(3)); //向列表中添加數(shù)據(jù)
set1.add(new Socket()); //向列表中添加數(shù)據(jù)
int size=set1.size();
System.out.println("Set1集合的大小為:" + size);
Set set2=new HashSet();
set2.add("book"); //向列表中添加數(shù)據(jù)
set2.add(new Long(3)); //向列表中添加數(shù)據(jù)
int size2=set2.size();
System.out.println("Set2集合的大小為:" + size2);
set1.addAll(set2);
System.out.println("合并后Set1集合的大小為:" + set1.size());
set1.removeAll(set2);
System.out.println("拆分后Set1集合的大小為: " + set1.size());
set1.retainAll(set2);
System.out.println("Set1和Set2集合交集的部分:" + set1.size());
}
輸出結(jié)果:
Set1集合的大小為:4
Set2集合的大小為:2
合并后Set1集合的大小為:6
拆分后Set1集合的大小為: 4
Set1和Set2集合交集的部分:2
列表的能力:
在指定的位置插入
void add(int index, Obeject newElement)
取得某個(gè)索引的元素
Object get(int index)
設(shè)置某個(gè)索引的元素
Object set(int index, Object newElement)
刪除某個(gè)索引的元素
Object remove(int index)
代碼示例
class Persons{
public String name ;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
Persons(){
}
Persons(String name){
this.name = name;
}
public static void main(String[] args) {
List<Persons> persons = new ArrayList<Persons>();
persons.add(new Persons("張三"));
persons.add(new Persons("李四"));
persons.add(new Persons("王五"));
persons.add(new Persons("趙六"));
System.out.println(persons.get(0).getName());//這里僅作輸出查看
persons.set(1,new Persons("趙六"));
persons.remove(2);
for(Persons person: persons){
System.out.println(person.getName());
}
}
}
輸出結(jié)果:
get方法:張三
張三
趙六
趙六
3.3.3 Map接口
- Map與Collection并列存在。用于保存具有映射關(guān)系的數(shù)據(jù):Key-Value
- Map 中的 key 和 value 都可以是任何引用類型的數(shù)據(jù)
- Map 中的 key 用Set來(lái)存放,不允許重復(fù),即同一個(gè) Map 對(duì)象所對(duì)應(yīng)的類,須重寫(xiě)hashCode()和equals()方法。
- 常用String類作為Map的“鍵”。
- key 和 value 之間存在單向一對(duì)一關(guān)系,即通過(guò)指定的 key 總能找到唯一的、確定的 value。
Map體系繼承樹(shù)

3.3.3.1 Map常用方法
添加、刪除操作:
Object put(Object key,Object value)
Object remove(Object key)
void putAll(Map t)
void clear()
元視圖操作的方法:
Set keySet()
Collection values()
Set entrySet()
元素查詢的操作:
Object get(Object key)
boolean containsKey(Object key)
boolean containsValue(Object value)
int size()
boolean isEmpty()
boolean equals(Object obj)
3.3.3.2 Map實(shí)現(xiàn)類之一 HashMap
- Map接口的常用實(shí)現(xiàn)類:HashMap、TreeMap和Properties。
- HashMap是 Map 接口使用頻率最高的實(shí)現(xiàn)類。
- 允許使用null鍵和null值,與HashSet一樣,不保證映射的順序。
- HashMap 判斷兩個(gè) key 相等的標(biāo)準(zhǔn)是:兩個(gè) key 通過(guò) equals() 方法返回 true,hashCode 值也相等。
- HashMap 判斷兩個(gè) value相等的標(biāo)準(zhǔn)是:兩個(gè) value 通過(guò) equals() 方法返回 true。
3.3.3.3 Map實(shí)現(xiàn)類之二 LinkedHashMap
- LinkedHashMap 是 HashMap 的子類
- 與LinkedHashSet類似,LinkedHashMap 可以維護(hù) Map 的迭代順序:迭代順序與 Key-Value 對(duì)的插入順序一致
3.3.3.4 Map實(shí)現(xiàn)類之三 TreeMap
- TreeMap存儲(chǔ) Key-Value 對(duì)時(shí),需要根據(jù) key-value 對(duì)進(jìn)行排序。TreeMap 可以保證所有的 Key-Value 對(duì)處于有序狀態(tài)。
- TreeMap 的 Key 的排序:
- 自然排序:TreeMap 的所有的 Key 必須實(shí)現(xiàn) Comparable 接口,而且所有的 Key 應(yīng)該是同一個(gè)類的對(duì)象,否則將會(huì)拋出 ClasssCastException
- 定制排序:創(chuàng)建 TreeMap 時(shí),傳入一個(gè) Comparator 對(duì)象,該對(duì)象負(fù)責(zé)對(duì) TreeMap 中的所有 key 進(jìn)行排序。此時(shí)不需要 Map 的 Key 實(shí)現(xiàn) Comparable 接口
- TreeMap判斷兩個(gè)key相等的標(biāo)準(zhǔn):兩個(gè)key通過(guò)compareTo()方法或者compare()方法返回0。
- 若使用自定義類作為T(mén)reeMap的key,所屬類需要重寫(xiě)equals()和hashCode()方法,且equals()方法返回true時(shí),compareTo()方法應(yīng)返回0。
案例6
package day07;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;
class Code implements Comparable<Code> {
private int id;
public Code(int id) {
this.id = id;
}
public int getId() {
return id;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (obj instanceof Code) {
Code c = (Code) obj;
if (c.id == this.id) {
return true;
}
}
return false;
}
@Override
public int hashCode() {
// TODO Auto-generated method stub
return id;
}
@Override
public String toString() {
return "Code [id=" + id + "]";
}
@Override
public int compareTo(Code o) {
if (this.id > o.id) {
return 1;
} else if (this.id < o.id) {
return -1;
} else {
return 0;
}
}
}
class Person1 {
private Code id;// 身份
private String name;// 姓名
public Person1(String name, Code id) {
this.name = name;
this.id = id;
}
public String getName() {
return name;
}
public Code getId() {
return id;
}
@Override
public String toString() {
return "Person1 [id=" + id + ", name=" + name + "]";
}
}
public class Treemap {
public static void main(String[] args) {
// Comparable 與Comparator
TreeMap<Code, Person1> map = new TreeMap<Code, Person1>();
// 購(gòu)物車 Map
Person1 p1 = new Person1("張三", new Code(1111));
Person1 p2 = new Person1("李四", new Code(1112));
Person1 p3 = new Person1("王五", new Code(1113));
Person1 p4 = new Person1("趙六", new Code(1114));
Person1 p5 = new Person1("周七", new Code(1111));
map.put(p1.getId(), p1);
map.put(p2.getId(), p2);
map.put(p3.getId(), p3);
map.put(p4.getId(), p4);
map.put(p5.getId(), p5);
System.out.println("長(zhǎng)度" + map.size());
Set<Entry<Code, Person1>> set = map.entrySet();
Iterator<Entry<Code, Person1>> it = set.iterator();
while (it.hasNext()) {
Entry<Code, Person1> entry = it.next();
Person1 p = entry.getValue();
System.out.println(p.getId() + "---" + p.getName());
}
Person1 p = map.get(new Code(1111));
System.out.println("xxxxxx" + p);
}
}
輸出結(jié)果:
長(zhǎng)度4
Code [id=1111]---周七
Code [id=1112]---李四
Code [id=1113]---王五
Code [id=1114]---趙六
xxxxxxPerson1 [id=Code [id=1111], name=周七]
3.3.3.4 Map實(shí)現(xiàn)類之四 Hashtable
- Hashtable是個(gè)古老的 Map 實(shí)現(xiàn)類,線程安全。
- 與HashMap不同,Hashtable 不允許使用 null 作為 key 和 value
- 與HashMap一樣,Hashtable 也不能保證其中 Key-Value 對(duì)的順序
- Hashtable判斷兩個(gè)key相等、兩個(gè)value相等的標(biāo)準(zhǔn),與hashMap一致。
HashMap和Hashtable的區(qū)別
一.歷史原因:Hashtable是基于陳舊的Dictionary類的,HashMap是Java 1.2引進(jìn)的Map接口的一個(gè)實(shí)現(xiàn)
二.同步性:Hashtable是線程安全的,也就是說(shuō)是同步的,而HashMap是線程序不安全的,不是同步的
三.值:只有HashMap可以讓你將空值作為一個(gè)表的條目的key或value
3.3.3.5 Map實(shí)現(xiàn)類之五 Properties
- Properties 類是 Hashtable 的子類,該對(duì)象用于處理屬性文件
- 由于屬性文件里的 key、value 都是字符串類型,所以 Properties 里的 key 和 value 都是字符串類型
- 存取數(shù)據(jù)時(shí),建議使用setProperty(String key,String value)方法和getProperty(String key)方法
代碼示例
import java.util.Iterator;
import java.util.Properties;
import java.util.Set;
public class PropertiesDemo {
public static void main(String[] args) {
new PropertiesDemo();
Properties pro = new Properties();
pro.put("name", "root");
pro.put("pass", "root");
pro.put("url", "jdbc:mysql://localhost:3306/db");
String name = pro.getProperty("name");
System.out.println(name);
// 遍歷
/*Set<Object> set = pro.keySet();
Iterator<Object> it = set.iterator();
while (it.hasNext()) {
System.out.println(pro.get(it.next()));
}*/
Set<String> set = pro.stringPropertyNames();
Iterator<String> it = set.iterator();
while (it.hasNext()) {
System.out.println(pro.get(it.next()));
}
}
}
輸出結(jié)果:
root
root
jdbc:mysql://localhost:3306/db
root
但是,常獲取數(shù)據(jù)庫(kù)密碼鏈接等是通過(guò)外部文件得到
{
Properties pro = new Properties();
try {
InputStream is = getClass().getResourceAsStream("jdbc.properties");
pro.load(is);
System.out.println("user=="+pro.get("user"));
System.out.println("password=="+pro.get("password"));
System.out.println("url==="+pro.get("url"));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
3.3.4 操縱集合的工具類 Collections
- Collections 是一個(gè)操作 Set、List 和 Map 等集合的工具類
- Collections 中提供了一系列靜態(tài)的方法對(duì)集合元素進(jìn)行排序、查詢和修改等操作,還提供了對(duì)集合對(duì)象設(shè)置不可變、對(duì)集合對(duì)象實(shí)現(xiàn)同步控制等方法
- 排序操作:(均為static方法)
- reverse(List):反轉(zhuǎn) List 中元素的順序
- shuffle(List):對(duì) List 集合元素進(jìn)行隨機(jī)排序
- sort(List):根據(jù)元素的自然順序?qū)χ付?List 集合元素按升序排序
- sort(List,Comparator):根據(jù)指定的 Comparator 產(chǎn)生的順序?qū)?List 集合元素進(jìn)行排序
- swap(List,int, int):將指定 list 集合中的 i 處元素和 j 處元素進(jìn)行交換
查找、替換
- Object max(Collection):根據(jù)元素的自然順序,返回給定集合中的最大元素
- Object max(Collection,Comparator):根據(jù) Comparator 指定的順序,返回給定集合中的最大元素
- Object min(Collection)
- Object min(Collection,Comparator)
- int frequency(Collection,Object):返回指定集合中指定元素的出現(xiàn)次數(shù)
- void copy(List dest,List src):將src中的內(nèi)容復(fù)制到dest中
- boolean replaceAll(List list,Object oldVal,Object newVal):使用新值替換 List 對(duì)象的所有舊值
同步控制
Collections 類中提供了多個(gè) synchronizedXxx() 方法,該方法可使將指定集合包裝成線程同步的集合,從而可以解決多線程并發(fā)訪問(wèn)集合時(shí)的線程安全問(wèn)題

3.3.4.1 Collection和Collections區(qū)別
Collections是個(gè)java.util下的類,它包含有各種有關(guān)集合操作的靜態(tài)方法。
Collection是個(gè)java.util下的接口,它是各種集合結(jié)構(gòu)的父接口。
3.3.5 Enumeration
Enumeration 接口是 Iterator 迭代器的 “古老版本”

案例7
Enumeration stringEnum = new StringTokenizer("a-b*c-d-e-g", "-");
while(stringEnum.hasMoreElements()){
Object obj = stringEnum.nextElement();
System.out.println(obj);
}
輸出結(jié)果:
a
b*c
d
e
g