java集合容器

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
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,663評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,125評(píng)論 3 414
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 175,506評(píng)論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 62,614評(píng)論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,402評(píng)論 6 404
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 54,934評(píng)論 1 321
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,021評(píng)論 3 440
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 42,168評(píng)論 0 287
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,690評(píng)論 1 333
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,596評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,784評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,288評(píng)論 5 357
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,027評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 34,404評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 35,662評(píng)論 1 280
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,398評(píng)論 3 390
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,743評(píng)論 2 370

推薦閱讀更多精彩內(nèi)容

  • Collection ├List │├LinkedList │├ArrayList │└Vector │└Stac...
    AndyZX閱讀 884評(píng)論 0 1
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語(yǔ)法,類相關(guān)的語(yǔ)法,內(nèi)部類的語(yǔ)法,繼承相關(guān)的語(yǔ)法,異常的語(yǔ)法,線程的語(yǔ)...
    子非魚(yú)_t_閱讀 31,707評(píng)論 18 399
  • java筆記第一天 == 和 equals ==比較的比較的是兩個(gè)變量的值是否相等,對(duì)于引用型變量表示的是兩個(gè)變量...
    jmychou閱讀 1,507評(píng)論 0 3
  • 集合類簡(jiǎn)介 為什么出現(xiàn)集合類?面向?qū)ο笳Z(yǔ)言對(duì)事物的體現(xiàn)都是以對(duì)象的形式,所以為了方便對(duì)多個(gè)對(duì)象的操作,就要對(duì)對(duì)象進(jìn)...
    阿敏其人閱讀 1,432評(píng)論 0 7
  • 上高中時(shí)和同學(xué)說(shuō),我要玩到29歲,然后結(jié)婚。同班的一個(gè)男生說(shuō),到時(shí)候誰(shuí)來(lái)收拾這場(chǎng)殘局呀。氣得我追打他整個(gè)教室。 現(xiàn)...
    春霖桃語(yǔ)閱讀 211評(píng)論 0 0