欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

java集合超詳細(xì)(最新推薦)

 更新時(shí)間:2024年12月13日 15:18:52   作者:故離ovo  
在內(nèi)存中申請(qǐng)一塊空間用來存儲(chǔ)數(shù)據(jù),在Java中集合就是替換掉定長(zhǎng)的數(shù)組的一種引用數(shù)據(jù)類型,本文介紹java集合超詳細(xì)講解,感興趣的朋友一起看看吧

1 - 概述

所有的集合類和集合接口都在java.util包下。

在內(nèi)存中申請(qǐng)一塊空間用來存儲(chǔ)數(shù)據(jù),在Java中集合就是替換掉定長(zhǎng)的數(shù)組的一種引用數(shù)據(jù)類型。

2 - 集合與數(shù)組的區(qū)別

長(zhǎng)度區(qū)別

數(shù)組長(zhǎng)度固定,定義長(zhǎng)了造成內(nèi)存空間的浪費(fèi),定義短了不夠用。

集合大小可以變,用多少空間拿多少空間。

內(nèi)容區(qū)別

數(shù)組可以存儲(chǔ)基本數(shù)據(jù)類型和引用數(shù)據(jù)類型

集合中能存儲(chǔ)引用數(shù)據(jù)類型(存儲(chǔ)的為對(duì)象的內(nèi)存地址)

list.add(100);//為自動(dòng)裝箱,100為Integer包裝的

元素區(qū)別

數(shù)組中只能存儲(chǔ)同一種類型成員

集合中可以存儲(chǔ)不同類型數(shù)據(jù)(一般情況下也只存儲(chǔ)同一種類型的數(shù)據(jù))

集合結(jié)構(gòu)

在java中每一個(gè)不同的集合,底層會(huì)對(duì)應(yīng)不同的數(shù)據(jù)結(jié)構(gòu)。往不同的集合中
存儲(chǔ)元素,等于將數(shù)據(jù)放到了不同的數(shù)據(jù)結(jié)構(gòu)當(dāng)中。什么是數(shù)據(jù)結(jié)構(gòu)?數(shù)據(jù)存儲(chǔ)的
結(jié)構(gòu)就是數(shù)據(jù)結(jié)構(gòu)。不同的數(shù)據(jù)結(jié)構(gòu),數(shù)據(jù)存儲(chǔ)方式不同。

  • 單列集合 Collection
    • List可以重復(fù):ArrayList/LinkedList
    • Set不可重復(fù):HashSet/TreeSet

(大量文字插入會(huì)導(dǎo)致圖片不清,所以在此進(jìn)行更詳細(xì)的描述)

  • List特點(diǎn):此處順序并不是大小順序,而是存入數(shù)據(jù)的先后順序。有序因?yàn)長(zhǎng)ist集合都有下標(biāo),下標(biāo)從0開始,以遞增。
  • Set特點(diǎn):取出順序不一定為存入順序,另外Set集合沒有下標(biāo)。
  • ArrayList是非線程安全的。
  • HashSet集合在new的時(shí)候,底層實(shí)際上new了一個(gè)HashMap集合。向HashSet集合中存儲(chǔ)元素,實(shí)際上是存儲(chǔ)到了HashMap的key中了。HashMap集合是一個(gè)Hash表數(shù)據(jù)結(jié)構(gòu)。
  • SortedSet集合存儲(chǔ)元素的特點(diǎn):由于繼承了Set集合,所以他的特點(diǎn)也是無序不可重復(fù),但是放在SortedSet集合中的元素可以自動(dòng)排序。放到該集合中的元素是自動(dòng)按照大小順序排序的。
  • TreeSet集合底層實(shí)際上是TreeMap。TreeSet集合在new的時(shí)候,底層實(shí)際上new了一個(gè)TreeMap集合。向TreeSet集合中存儲(chǔ)元素,實(shí)際上是存儲(chǔ)到了TreeMap的key中了。TreeMap集合是一個(gè)二叉樹數(shù)據(jù)結(jié)構(gòu)。

雙列集合Map:HashMap/TreeMap

粗體是接口 斜體是實(shí)現(xiàn)類

3- Collection集合

3.1 - 概述

單列集合的頂層接口,既然是接口就不能直接使用,需要通過實(shí)現(xiàn)類!~

3.2 - Collection集合的的常用方法

方法名說明
boolean add(E e)添加元素到集合的末尾(追加)
boolean remove(Object o)刪除指定的元素,成功則返回true(底層調(diào)用equles)
void clear()清空集合
boolean contains(Object o)判斷元素在集合中是否存在,存在則返回true(底層調(diào)用equles)
boolean isEmpty()判斷集合是否為空,空則返回true
int size()返回集合中元素個(gè)數(shù)
import java.util.ArrayList;
import java.util.Collection;
/**
 * @author Mr.樂
 * @Description
 */
public class Collection_01 {
    public static void main(String[] args) {
        //父類的引用指向子類的對(duì)象,形成多態(tài)
        Collection<String> con = new ArrayList<>();
        //追加的方式添加元素
        con.add("東邪");
        con.add("西毒");
        con.add("南帝");
        con.add("北丐");
        con.add("中神通");
        //刪除,通過元素名稱刪除元素
        System.out.println(con.remove("西毒"));
        //判斷集合中是否包含指定參數(shù)元素
        System.out.println(con.contains("西毒"));  //false
        System.out.println(con.contains("東邪"));    //true
        //獲取集合中元素個(gè)數(shù)
        System.out.println(con.size());
        //判斷是否為空
        System.out.println(con.isEmpty());//false
        //清空集合
        con.clear();
        //判斷是否為空
        System.out.println(con.isEmpty());//true
        System.out.println(con);//打印集合的元素
    }
}

3.3 - Collection集合的遍歷

以下迭代方式,是所有Collection通用的一種方式。在Map集合中不能使用,在所有的Collection以及子類中使用。

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
/**
 * @author Mr.樂
 * @Description  Collection 集合的遍歷
 */
public class Connection_02 {
    public static void main(String[] args) {
        //多態(tài)
        Collection<String> con = new ArrayList<>();
        //添加元素
        con.add("abc");
        con.add("def");
        con.add("100");
        con.add("444");
        //Collection集合的遍歷方式
        //因?yàn)闆]有索引的概念,所以Collection集合不能使用fori進(jìn)行遍歷
        //增強(qiáng)版for循環(huán),其實(shí)底層使用的也是迭代器,在字節(jié)碼文件中查看
        for (String str : con) {
            System.out.print(str + "\t");
        }
        System.out.println();//換行
        //迭代器,集合專屬的遍歷工具
        Iterator<String> it = con.iterator();//創(chuàng)建迭代器對(duì)象
        while (it.hasNext()){//判斷下一個(gè)位置是否有元素
            System.out.print(it.next() + "\t");//獲取到下一個(gè)位置的元素
        }
    }
}

3.4-Iterator的remove

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
/**
 * @author Mr.樂
 * @Description
 */
public class Connection_remove {
    public static void main(String[] args) {
        // 創(chuàng)建集合
        Collection c = new ArrayList();
        // 注意:此時(shí)獲取的迭代器,指向的是那是集合中沒有元素狀態(tài)下的迭代器。
        // 一定要注意:集合結(jié)構(gòu)只要發(fā)生改變,迭代器必須重新獲取。
        // 當(dāng)集合結(jié)構(gòu)發(fā)生了改變,迭代器沒有重新獲取時(shí),調(diào)用next()方法時(shí):java.util.ConcurrentModificationException
        Iterator it = c.iterator();
        // 添加元素
        c.add(1); // Integer類型
        c.add(2);
        c.add(3);
        // 獲取迭代器
        //Iterator it = c.iterator();
        /*while(it.hasNext()){
            // 編寫代碼時(shí)next()方法返回值類型必須是Object。
            // Integer i = it.next();
            Object obj = it.next();
            System.out.println(obj);
        }*/
        Collection c2 = new ArrayList();
        c2.add("abc");
        c2.add("def");
        c2.add("xyz");
        Iterator it2 = c2.iterator();
        while(it2.hasNext()){
            Object o = it2.next();
            // 刪除元素
            // 刪除元素之后,集合的結(jié)構(gòu)發(fā)生了變化,應(yīng)該重新去獲取迭代器
            // 但是,循環(huán)下一次的時(shí)候并沒有重新獲取迭代器,所以會(huì)出現(xiàn)異常:java.util.ConcurrentModificationException
            // 出異常根本原因是:集合中元素刪除了,但是沒有更新迭代器(迭代器不知道集合變化了)
            //c2.remove(o); // 直接通過集合去刪除元素,沒有通知迭代器。(導(dǎo)致迭代器的快照和原集合狀態(tài)不同。)
            // 使用迭代器來刪除可以嗎?
            // 迭代器去刪除時(shí),會(huì)自動(dòng)更新迭代器,并且更新集合(刪除集合中的元素)。
            it2.remove(); // 刪除的一定是迭代器指向的當(dāng)前元素。
            System.out.println(o);
        }
        System.out.println(c2.size()); //0
    }
}

4-List

原型ArrayList<E>

  • ArrayList是一個(gè)List接口的實(shí)現(xiàn)類,底層使用的是一個(gè)可以調(diào)整大小的數(shù)組實(shí)現(xiàn)的。
  • <E>:是一種特殊的數(shù)據(jù)類型(引用數(shù)據(jù)類型) -- 泛型
    • ArrayList<String> 或者 ArrayList<Integer> 或者 ArrayList<Student>

4.1 - ArrayList構(gòu)造和添加方法

方法名說明
public ArrayList<E>()創(chuàng)建一個(gè)空集合
public boolean add(E e)將指定的參數(shù)元素追加到集合的末尾
public void add(int index ,E e)在集合的指定位置添加指定的元素(插入元素)
public void addAll(E object)用于將指定集合中所有元素添加到當(dāng)前集合中
/**
 * @author Mr.樂
 * @Description  ArrayList構(gòu)造和添加方法
 */
public class ArrayList_01 {
    public static void main(String[] args) {
        //創(chuàng)建空集合
        ArrayList<String> list = new ArrayList<>();//泛型定義為String
        //采用默認(rèn)追加的方式添加元素
        System.out.println(list.add("劉德華"));
        System.out.println(list.add("張學(xué)友"));
        System.out.println(list.add("郭富城"));
        System.out.println(list.add("黎明"));
        //插入的方式添加元素
//        list.add(10,"譚詠麟");//插入元素方法索引值不能大于集合中元素個(gè)數(shù)
//        list.add(4,"譚詠麟");//表示在集合中最后位置插入元素,與追加相同
        list.add(1,"譚詠麟");//指定位置插入元素,索引位置之后的元素會(huì)自動(dòng)向后進(jìn)行移動(dòng)
        ArrayList<String> newList = new ArrayList<>();//創(chuàng)建新的集合
        newList.add("小沈陽");
        newList.add("宋小寶");
        newList.add("趙四");
        newList.add("劉能");
        //查看集合中的元素
        System.out.println("原集合內(nèi)部元素:" + list);
        System.out.println("新集合內(nèi)部元素:" + newList);
        list.addAll(newList); //將新集合全部元素添加到原集合中
        System.out.println("原集合內(nèi)部元素:" + list);
    }
}

4.2 - ArrayList集合常用方法

方法名說明
public boolean remove(Object o)刪除指定的元素,成功則返回true
public E remove(int index)刪除指定索引位置的元素,返回被刪除的元素
public E set(int index,E e)修改指定索引位置的元素,返回修改前的元素
public E get(int index)獲取指定索引對(duì)應(yīng)的元素
public int size()獲取結(jié)合中元素個(gè)數(shù)
import java.util.ArrayList;
import java.util.Iterator;
/**
 * @author Mr.樂
 * @Description   ArrayList集合常用方法
 */
public class ArrayList_02 {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        //追加方式添加元素
        list.add("東邪");
        list.add("西毒");
        list.add("南帝");
        list.add("北丐");
        list.add("中神通");
        //刪除
        System.out.println(list.remove("西毒"));//通過元素名稱刪除,返回boolean
        System.out.println(list.remove(1));//通過索引刪除元素,返回被刪除元素名
        //修改
        System.out.println(list.set(1,"西毒"));//指定索引位置修改元素,并返回被修改元素
        System.out.println("原集合中元素有:" + list);
        //獲取方法
        System.out.println(list.get(1));//通過指定索引位置獲取集合元素
        //獲取集合元素個(gè)數(shù)
        System.out.println(list.size());
        //集合的遍歷,普通for循環(huán)
        for (int i = 0; i < list.size(); i++) {
            System.out.print(list.get(i) + "\t");
        }
        System.out.println();
        //增強(qiáng)版for循環(huán)
        for (String name : list) {
            System.out.print(name+ "\t");
        }
        System.out.println();
        //迭代器
        Iterator<String> it = list.iterator();//創(chuàng)建迭代器
        while (it.hasNext()){//判斷下一個(gè)位置是否有元素
            System.out.print(it.next() + "\t");  //next方法表示獲取下一個(gè)位置的元素
        }
        System.out.println();
        //Stream流
        list.stream().forEach(System.out::println);
    }
}

4.3 -ArrayList實(shí)現(xiàn)原理

底層代碼:

屬性:

DEFAULT_CAPACITY = 10 默認(rèn)長(zhǎng)度,初始化容量為10Object[] EMPTY_ELEMENTDATA = {} //有參構(gòu)造所創(chuàng)建Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {} //無參構(gòu)造所創(chuàng)建的Object[] elementData;底層為Object類型的數(shù)組,存儲(chǔ)的元素都在此。int size 實(shí)際存放的個(gè)數(shù)

構(gòu)造方法 :

//一個(gè)參數(shù)的構(gòu)造
public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }
//參數(shù)如果大于零,則為創(chuàng)建數(shù)組的長(zhǎng)度;
//參數(shù)如果等于零,EMPTY_ELEMENTDATA;
//參數(shù)如果小于0,拋出異常。
//無參構(gòu)造
  public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }
//DEFAULTCAPACITY_EMPTY_ELEMENTDATA  new對(duì)象時(shí)默認(rèn)為0 當(dāng)添加第一個(gè)元素的時(shí)候,數(shù)組擴(kuò)容至10

add方法源碼:(jdk1.8與之不同,此處為jdk16)

//源碼
public boolean add(E e) {
        modCount++;//操作次數(shù)
        add(e, elementData, size);
//e 操作對(duì)象;  elementData 底層操作的數(shù)組;size 默認(rèn)大小0
        return true;
    }
------------------------------------------------
 private void add(E e, Object[] elementData, int s) {
        if (s == elementData.length)//ture
            elementData = grow();
        elementData[s] = e;  //存數(shù)據(jù)
        size = s + 1; //最小需要長(zhǎng)度
    }
----------------------------------------------------------
 private Object[] grow() {
        return grow(size + 1);
    }
-----------------------------------------------------
 private Object[] grow(int minCapacity) { //初始傳入為size+1  為1
        int oldCapacity = elementData.length; //初始為0
        if (oldCapacity > 0 || elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
       //if條件為初始數(shù)組長(zhǎng)度>0或者數(shù)組不是無參構(gòu)造構(gòu)建的
            int newCapacity = ArraysSupport.newLength(oldCapacity, //舊數(shù)組的長(zhǎng)度
                    minCapacity - oldCapacity, /* minimum growth */  
                    //最小需要長(zhǎng)度-舊數(shù)組的長(zhǎng)度  大于0代表空間不足
                    oldCapacity >> 1           /* preferred growth */);
                   //二進(jìn)制位右移1位  位舊數(shù)組長(zhǎng)度/2
            return elementData = Arrays.copyOf(elementData, newCapacity);
            將數(shù)據(jù)放入新數(shù)組中
        } else {
            return elementData = new Object[Math.max(DEFAULT_CAPACITY, minCapacity)];
            //數(shù)組長(zhǎng)度  DEFAULT_CAPACITY為10  此處代表無參構(gòu)造默認(rèn)長(zhǎng)度為10
        }
    }
----------------------------------------------------
 public static int newLength(int oldLength, int minGrowth, int prefGrowth) {
        // assert oldLength >= 0
        // assert minGrowth > 0
        int newLength = Math.max(minGrowth, prefGrowth) + oldLength;
         //如果prefGrowth>minGrowth  擴(kuò)容1.5倍    minGrowth>prefGrowth為需要多少給多少
        if (newLength - MAX_ARRAY_LENGTH <= 0) {
     //MAX_ARRAY_LENGTH為int最大值   表示新數(shù)組長(zhǎng)度如果小于int的最大值
            return newLength;
        }
        return hugeLength(oldLength, minGrowth);
         //返回int最大值
    }

ArrayList集合底層是數(shù)組,怎么優(yōu)化?
盡可能少的擴(kuò)容。因?yàn)閿?shù)組擴(kuò)容效率比較低,建議在使用ArrayList集合 的時(shí)候預(yù)估計(jì)元素的個(gè)數(shù),給定一個(gè)初始化容量。

數(shù)組優(yōu)點(diǎn):
檢索效率比較高。(每個(gè)元素占用空間大小相同,內(nèi)存地址是連續(xù)的,知道首元素內(nèi)存地址,
然后知道下標(biāo),通過數(shù)學(xué)表達(dá)式計(jì)算出元素的內(nèi)存地址,所以檢索效率最高。)

數(shù)組缺點(diǎn):
隨機(jī)增刪元素效率比較低。
另外數(shù)組無法存儲(chǔ)大數(shù)據(jù)量。(很難找到一塊非常巨大的連續(xù)的內(nèi)存空間。)

向數(shù)組末尾添加元素,效率很高,不受影響。

4.4 -LinkedList實(shí)現(xiàn)原理

底層代碼

屬性:

    transient int size = 0;//初始長(zhǎng)度
    transient Node<E> first;//頭節(jié)點(diǎn)
    transient Node<E> last;//尾節(jié)點(diǎn)

add方法源碼:(jdk1.8與之不同,此處為jdk16)

public boolean add(E e) {
        linkLast(e);
        return true;
    }
--------------------------------------
void linkLast(E e) {
        final Node<E> l = last; //初始為null
        final Node<E> newNode = new Node<>(l, e, null);
    //參數(shù)1:位上一個(gè)節(jié)點(diǎn)的內(nèi)存地址,參數(shù)2:e為插入的數(shù)據(jù),參數(shù)3:下一個(gè)節(jié)點(diǎn)的內(nèi)存地址
        last = newNode; // 最后節(jié)點(diǎn)為新節(jié)點(diǎn)
        if (l == null)  //如果newNode的前一個(gè)節(jié)點(diǎn)為null,則將新節(jié)點(diǎn)賦給first
            first = newNode;
        else
            l.next = newNode;  //尾節(jié)點(diǎn)下一個(gè)節(jié)點(diǎn)為新節(jié)點(diǎn)
        size++;//大小
        modCount++;//操作數(shù)
    }

4.5-LinkedList和ArrayList

LinkedList和ArrayList方法一樣,只是底層實(shí)現(xiàn)不一樣。ArrayList底層為數(shù)組存儲(chǔ),LinkedList是以雙向鏈表存儲(chǔ)。LinkedList集合沒有初始化容量。最初這個(gè)鏈表中沒有任何元素。first和last引用都是null。

鏈表的優(yōu)點(diǎn):
由于鏈表上的元素在空間存儲(chǔ)上內(nèi)存地址不連續(xù)。
所以隨機(jī)增刪元素的時(shí)候不會(huì)有大量元素位移,因此隨機(jī)增刪效率較高。
在以后的開發(fā)中,如果遇到隨機(jī)增刪集合中元素的業(yè)務(wù)比較多時(shí),建議
使用LinkedList。

鏈表的缺點(diǎn):
不能通過數(shù)學(xué)表達(dá)式計(jì)算被查找元素的內(nèi)存地址,每一次查找都是從頭
節(jié)點(diǎn)開始遍歷,直到找到為止。所以LinkedList集合檢索/查找的效率
較低。

ArrayList:把檢索發(fā)揮到極致。(末尾添加元素效率還是很高的。)
LinkedList:把隨機(jī)增刪發(fā)揮到極致。
加元素都是往末尾添加,所以ArrayList用的比LinkedList多。

4.6 -Vector

1、底層也是一個(gè)數(shù)組。
2、初始化容量:10
3、怎么擴(kuò)容的?
擴(kuò)容之后是原容量的2倍。
10--> 20 --> 40 --> 80
4、Vector中所有的方法都是線程同步的,都帶有synchronized關(guān)鍵字,
是線程安全的。效率比較低,使用較少了。
5、怎么將一個(gè)線程不安全的ArrayList集合轉(zhuǎn)換成線程安全的呢?
使用集合工具類:
java.util.Collections;
java.util.Collection 是集合接口。
java.util.Collections 是集合工具類。
Collections.synchronizedList();//將及格轉(zhuǎn)換為線程安全的。

5-Set

5.1 -概述

  • Set集合也是一個(gè)接口,繼承自Collection,與List類似,都需要通過實(shí)現(xiàn)類來進(jìn)行操作。
  • 特點(diǎn)
    • 不允許包含重復(fù)的值
    • 沒有索引(就不能使用普通的for循環(huán)進(jìn)行遍歷)
import java.util.HashSet;
import java.util.Set;
/**
 * @author Mr.樂
 * @Description Set集合
 */
public class Demo01 {
    public static void main(String[] args) {
        //使用多態(tài),父類的引用指向子類對(duì)象
        Set<String> set = new HashSet<>();
        //添加元素
        set.add("黃固");
        set.add("歐陽鋒");
        set.add("段智興");
        set.add("洪七公");
        set.add("段智興");
        System.out.println(set);//打印集合
         //[洪七公, 黃固, 歐陽鋒, 段智興]
        //HashSet集合對(duì)于元素的讀寫順序不做保證
        //相同的元素,多次存儲(chǔ),只能保留一個(gè),并且不會(huì)報(bào)錯(cuò)
        //List集合可以存儲(chǔ)重復(fù)元素,Set集合不行
    }
}

例:雙色球

import java.util.Random;
import java.util.TreeSet;
/**
 * @author Mr.樂
 * @Description  雙色球 -Set版
 */
public class Demo02 {
    public static void main(String[] args) {
        Random ran = new Random();//創(chuàng)建隨機(jī)類對(duì)象
        int blueBall = ran.nextInt(16) + 1;
//        HashSet<Integer> redBalls = new HashSet<>();//創(chuàng)建集合用來存儲(chǔ)紅球
        TreeSet<Object> redBalls = new TreeSet<>();//TreeSet集合自帶排序規(guī)則
        while (redBalls.size() < 6){
            redBalls.add(ran.nextInt(33) + 1);//將當(dāng)前生成的紅球直接存進(jìn)集合中
            //因?yàn)镾et集合不能存儲(chǔ)重復(fù)的元素,所以去重的操作可以省略不做。
        }
        System.out.println("紅球:" + redBalls + "籃球 [" + blueBall + "]");
    }
}

5.2 -哈希值

Set集合的去重原理使用的是哈希值。

哈希值就是JDK根據(jù)對(duì)象地址 或者 字符串 或者數(shù)值 通過自己內(nèi)部的計(jì)算出來的一個(gè)整數(shù)類型數(shù)據(jù)

  • public int hashCode() - 用來獲取哈希值,來自于Object頂層類
  • 對(duì)象的哈希值特點(diǎn)
    • 同一個(gè)對(duì)象多次調(diào)用hashCode()方法,得到的結(jié)果是相同的。
    • 默認(rèn)情況下,不同的對(duì)象的哈希值也是不同的(特殊情況除外)
/**
 * @author Mr.樂
 * @Description  哈希值
 */
public class Demo03 {
    public static void main(String[] args) {
        //相同對(duì)象哈希值相同
        System.out.println("張三".hashCode());//774889
        System.out.println("張三".hashCode());//774889
        //不同對(duì)象哈希值不同
        System.out.println(new Object().hashCode());
        System.out.println(new Object().hashCode());
        //不同的對(duì)象的哈希值也有可能相同,例外情況
        System.out.println("輅鵝".hashCode());//1179395
        System.out.println("較鴉".hashCode());//1179395
        System.out.println("輒鸇".hashCode());//1179395
        System.out.println("輔鷨".hashCode());//1179395
    }
}

5.3 -HashSet去重原理

  • HashSet集合的特點(diǎn)
    • 底層結(jié)構(gòu)是“哈希表”
    • 集合對(duì)于讀寫順序不做保證
    • 沒有索引
    • Set集合中的內(nèi)容不能重復(fù)
/**
 * @author Mr.樂
 * @Description  HashSet去重原理
 */
public class Demo04 {
    public static void main(String[] args) {
        HashSet<Student> set = new HashSet<>();
        //添加元素
        set.add(new Student("黃固",28));
        set.add(new Student("歐陽鋒",38));
        set.add(new Student("段智興",48));
        set.add(new Student("洪七公",40));
        set.add(new Student("段智興",48));
        //從程序的角度來考慮,兩個(gè)段智興不是同一個(gè)對(duì)象,都有自己的存儲(chǔ)空間,所以哈希值也不一樣。
        for (Student stu : set) {
            System.out.println(stu);
        }
        /*
        重寫hashcode和equals
        Student{name='段智興', age=48}
        Student{name='歐陽鋒', age=38}
        Student{name='洪七公', age=40}
        Student{name='黃固', age=28}
         */
    }
}

5.4 -LinkedHashSet

  • 特點(diǎn)
    • LinkedHashSet是哈希表和鏈表實(shí)現(xiàn)的Set接口,具有可預(yù)測(cè)的讀寫順序。
    • 有鏈表來保證元素有序
    • 有哈希表來保證元素的唯一性
/**
 * @author Mr.樂
 * @Description LinkedHashSet
 */
public class Demo05 {
    public static void main(String[] args) {
        LinkedHashSet<String> set = new LinkedHashSet<>();
        //添加元素
        set.add("黃固");
        set.add("歐陽鋒");
        set.add("段智興");
        set.add("洪七公");
        set.add("段智興");//重復(fù)的元素不能存進(jìn)去
        System.out.println(set);//打印集合 [黃固, 歐陽鋒, 段智興, 洪七公]
    }
}

5.5 -TreeSet

1、TreeSet集合底層實(shí)際上是一個(gè)TreeMap

2、TreeMap集合底層是一個(gè)二叉樹。

3、放到TreeSet集合中的元素,等同于放到TreeMap集合key部分了。

4、TreeSet集合中的元素:無序不可重復(fù),但是可以按照元素的大小順序自動(dòng)排序。

import java.util.TreeSet;
public class TreeSetTest02 {
    public static void main(String[] args) {
        // 創(chuàng)建一個(gè)TreeSet集合
        TreeSet<String> ts = new TreeSet<>();
        // 添加String
        ts.add("zhangsan");
        ts.add("lisi");
        ts.add("wangwu");
        ts.add("zhangsi");
        ts.add("wangliu");
        // 遍歷
        for(String s : ts){
            // 按照字典順序,升序!
            System.out.println(s);
        }
        /*
        lisi
         wangliu
         wangwu
         zhangsan
         zhangsi
         */
        TreeSet<Integer> ts2 = new TreeSet<>();
        ts2.add(100);
        ts2.add(200);
        ts2.add(900);
        ts2.add(800);
        ts2.add(600);
        ts2.add(10);
        for(Integer elt : ts2){
            // 升序!
            System.out.println(elt);
        }
    }
}

5.5.1 -自定義排序規(guī)則

對(duì)于自定義的類無法排序,因?yàn)轭愔袑?duì)象之間沒有比較規(guī)則,不知道誰大誰小。

/**
 * @author Mr.樂
 * @Description  自定義比較器
 */
import java.util.TreeSet;
public class TreeSetTest04 {
    public static void main(String[] args) {
        Customer c1 = new Customer(32);
        Customer c2 = new Customer(20);
        Customer c3 = new Customer(30);
        Customer c4 = new Customer(25);
        // 創(chuàng)建TreeSet集合
        TreeSet<Customer> customers = new TreeSet<>();
        // 添加元素
        customers.add(c1);
        customers.add(c2);
        customers.add(c3);
        customers.add(c4);
        // 遍歷
        for (Customer c : customers){
            System.out.println(c);
        }
    }
}
// 放在TreeSet集合中的元素需要實(shí)現(xiàn)java.lang.Comparable接口。
// 并且實(shí)現(xiàn)compareTo方法。equals可以不寫。
class Customer implements Comparable<Customer>{
    int age;
    public Customer(int age){
        this.age = age;
    }
    // 需要在這個(gè)方法中編寫比較的邏輯,或者說比較的規(guī)則,按照什么進(jìn)行比較!
    // k.compareTo(t.key)
    // 拿著參數(shù)k和集合中的每一個(gè)k進(jìn)行比較,返回值可能是>0 <0 =0
    // 比較規(guī)則最終還是由程序員指定的:例如按照年齡升序?;蛘甙凑漳挲g降序。
    @Override
    public int compareTo(Customer c) { // c1.compareTo(c2);
        return c.age - this.age;
    }
    public String toString(){
        return "Customer[age="+age+"]";
    }
}

匿名內(nèi)部類方式

public class TreeSetTest05 {
    public static void main(String[] args) {
//        TreeSet<Student> ts = new TreeSet<>();//默認(rèn)排序規(guī)則
        TreeSet<Student> ts = new TreeSet<>(new Comparator<Student>() {
            @Override
            public int compare(Student o1, Student o2) {
                int res = o1.getAge() - o2.getAge();
                return 0 == res ? o1.getName().compareTo(o2.getName()) : res;
                 //三目運(yùn)算符  等于零用姓名排序
            }
        });//默認(rèn)排序規(guī)則
        //添加元素
        ts.add(new Student("Andy",19));
        ts.add(new Student("Jack",18));
        ts.add(new Student("Tom",21));
        ts.add(new Student("Lucy",17));
        ts.add(new Student("Bob",21)); //當(dāng)年齡相同時(shí),按照姓名的字典順序排序
        for (Student stu : ts) {
            System.out.println(stu);
        }
    }
}

Comparable和Comparator怎么選擇呢?
當(dāng)比較規(guī)則不會(huì)發(fā)生改變的時(shí)候,或者說當(dāng)比較規(guī)則只有1個(gè)的時(shí)候,建議實(shí)現(xiàn)Comparable接口。
如果比較規(guī)則有多個(gè),并且需要多個(gè)比較規(guī)則之間頻繁切換,建議使用Comparator接口。

6 -Map

6.1 -概述

  • 雙列集合:用來存儲(chǔ)鍵值對(duì)的集合。
    • interface Map<K,V> : K(key)鍵 ,V(value)值
    • 將鍵映射到值的對(duì)象,不能出現(xiàn)重復(fù)的鍵,每個(gè)鍵最多可以映射到一個(gè)值

1、Map和Collection沒有繼承關(guān)系。
2、Map集合以key和value的方式存儲(chǔ)數(shù)據(jù):鍵值對(duì)
key和value都是引用數(shù)據(jù)類型。
key和value都是存儲(chǔ)對(duì)象的內(nèi)存地址。
key起到主導(dǎo)的地位,value是key的一個(gè)附屬品。

例子:

學(xué)號(hào)(Key)姓名(Value)
STU001張三
STU002李四
STU003張三

6.2 -Map的基本方法

學(xué)號(hào)(Key)姓名(Value)
STU001張三
STU002李四
STU003張三
import java.util.HashMap;
import java.util.Map;
/**
 * @author Mr.樂
 * @Description  集合的基本方法
 */
public class Map01 {
    public static void main(String[] args) {
        Map<String,String> map = new HashMap<>();
        map.put("STU001","Andy");
        map.put("STU002","Jack");
        map.put("STU003","Tom");
        map.put("STU004","Bob");
        map.put("STU004","Smith");//設(shè)置(修改)
        //如果鍵不存在,則表示添加元素。如果鍵存在,則表示設(shè)置值。
        //刪除
        System.out.println(map.remove("STU003"));  //Tom
        //判斷是否包含
        System.out.println(map.containsKey("STU003"));  //false
        System.out.println(map.containsKey("STU004"));  //true
        System.out.println("-----------------------");
        System.out.println(map.containsValue("Tom"));  //false
        System.out.println(map.containsValue("Smith")); //true
        System.out.println("-----------------------");
        System.out.println(map.isEmpty());//判斷集合是否為空   false
        map.clear();//清空集合
        System.out.println(map.isEmpty()); //true
        System.out.println(map); //{}
    }
}

6.3 -Map集合的獲取功能

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
 * @author Mr.樂
 * @Description
 */
public class map_get {
    public static void main(String[] args) {
        Map<String,String> map = new HashMap<>();
        map.put("STU001","Andy");
        map.put("STU002","Jack");
        map.put("STU003","Tom");
        map.put("STU004","Bob");
        //get通過鍵獲取值
        System.out.println(map.get("STU003"));
        System.out.println("------------------");
        //keySet 獲取所有鍵的Set集合
        Set<String> keySet = map.keySet();
        System.out.println(keySet);
        //values  獲取所有值的Collection集合
        Collection<String> values = map.values();
        System.out.println(values);
        //entrySet  獲取所有鍵值對(duì)對(duì)象的Set集合
        Set<Map.Entry<String, String>> es = map.entrySet();
        //Map集合通過entrySet()方法轉(zhuǎn)換成的這個(gè)Set集合,Set集合中元素的類型是 Map.Entry<K,V>
        //Map.Entry和String一樣,都是一種類型的名字,只不過:Map.Entry是靜態(tài)內(nèi)部類,是Map中的靜態(tài)內(nèi)部類
        System.out.println(es);
         //[STU001=Andy, STU003=Tom, STU002=Jack, STU004=Bob]
         for (Map.Entry<String, String> entry:es){
             System.out.println("key:"+entry.getKey()+"    "+"value:"+entry.getValue());
         }
        /*
        key:STU001    value:Andy
        key:STU003    value:Tom
        key:STU002    value:Jack
        key:STU004    value:Bob
         */
    }
}

6.4 -哈希表

通過 數(shù)組 + 鏈表 實(shí)現(xiàn)的一種數(shù)據(jù)結(jié)構(gòu)

哈希表的構(gòu)造方法的參數(shù)是一個(gè)長(zhǎng)度為16個(gè)元素的數(shù)組,通過哈希值 % 16 的值,作為頭節(jié)點(diǎn)在數(shù)組中選擇對(duì)應(yīng)的位置,就形成了哈希表。

注:圖轉(zhuǎn)自動(dòng)力節(jié)點(diǎn)。

6.5 -HashMap

6.5.1 -底層源碼

 public class HashMap{
            // HashMap底層實(shí)際上就是一個(gè)數(shù)組。(一維數(shù)組)
            Node<K,V>[] table;
            // 靜態(tài)的內(nèi)部類HashMap.Node
            static class Node<K,V> {
                final int hash; // 哈希值(哈希值是key的hashCode()方法的執(zhí)行結(jié)果。hash值通過哈希函數(shù)/算法,可以轉(zhuǎn)換存儲(chǔ)成數(shù)組的下標(biāo)。)
                final K key; // 存儲(chǔ)到Map集合中的那個(gè)key
                V value; // 存儲(chǔ)到Map集合中的那個(gè)value
                Node<K,V> next; // 下一個(gè)節(jié)點(diǎn)的內(nèi)存地址。
            }
        }

6.5.2 -特點(diǎn)

1、無序,不可重復(fù)。
為什么無序? 因?yàn)椴灰欢⊕斓侥膫€(gè)單向鏈表上。
不可重復(fù)是怎么保證的? equals方法來保證HashMap集合的key不可重復(fù)。
如果key重復(fù)了,value會(huì)覆蓋。

2、放在HashMap集合key部分的元素其實(shí)就是放到HashSet集合中了。
所以HashSet集合中的元素也需要同時(shí)重寫hashCode()+equals()方法。
3、HashMap集合的默認(rèn)初始化容量是16,默認(rèn)加載因子是0.75
這個(gè)默認(rèn)加載因子是當(dāng)HashMap集合底層數(shù)組的容量達(dá)到75%的時(shí)候,數(shù)組以二叉樹開始擴(kuò)容。

重點(diǎn),記?。篐ashMap集合初始化容量必須是2的倍數(shù),這也是官方推薦的,
這是因?yàn)檫_(dá)到散列均勻,為了提高HashMap集合的存取效率,所必須的。

6.5.3 -注意

1.向Map集合中存,以及從Map集合中取,都是先調(diào)用key的hashCode方法,然后再調(diào)用equals方法!

equals方法有可能調(diào)用,也有可能不調(diào)用。

拿put(k,v)舉例,什么時(shí)候equals不會(huì)調(diào)用? k.hashCode()方法返回哈希值, 哈希值經(jīng)過哈希算法轉(zhuǎn)換成數(shù)組下標(biāo)。 數(shù)組下標(biāo)位置上如果是null,equals不需要執(zhí)行。 拿get(k)舉例,什么時(shí)候equals不會(huì)調(diào)用? k.hashCode()方法返回哈希值, 哈希值經(jīng)過哈希算法轉(zhuǎn)換成數(shù)組下標(biāo)。 數(shù)組下標(biāo)位置上如果是null,equals不需要執(zhí)行。

4.假設(shè)將所有的hashCode()方法返回值固定為某個(gè)值,那么會(huì)導(dǎo)致底層哈希表變成了 純單向鏈表。

這種情況我們成為:散列分布不均勻。

什么是散列分布均勻?

假設(shè)有100個(gè)元素,10個(gè)單向鏈表,那么每個(gè)單向鏈表上有10個(gè)節(jié)點(diǎn),這是最好的, 是散列分布均勻的。假設(shè)將所有的hashCode()方法返回值都設(shè)定為不一樣的值,可以嗎,有什么問題? 不行,因?yàn)檫@樣的話導(dǎo)致底層哈希表就成為一維數(shù)組了,沒有鏈表的概念了。 也是散列分布不均勻。散列分布均勻需要你重寫hashCode()方法時(shí)有一定的技巧。

7 -Properties

Properties是一個(gè)Map集合,繼承Hashtable,Properties的key和value都是String類型。 Properties被稱為屬性類對(duì)象。 Properties是線程安全的。

7.1 -方法

import java.io.IOException;
import java.util.Properties;
import java.util.Set;
/**
 * @author Mr.樂
 * @Description Properties特有方法
 */
public class Properties01 {
    public static void main(String[] args) throws IOException {
        Properties prop = new Properties();
        final String SRC = "./myConf.ini";//定義配置信息存儲(chǔ)路徑
//        mySave(prop,SRC);//存儲(chǔ)配置文件
        myLoad(prop,SRC);//加載配置文件信息
        //PASSWORD<--->123456
        //DATABASE<--->YX2115
        //PORT<--->3306
        //USERNAME<--->root
    }
    private static void myLoad(Properties prop, String src) throws IOException {
        FileReader fr = new FileReader(src);
        prop.load(fr);//通過流,加載指定路徑的配置文件
        fr.close();
        //遍歷
        Set<String> keySet = prop.stringPropertyNames();//獲取對(duì)象鍵的Set集合
        for (String key : keySet) {
            System.out.println(key + "<--->" + prop.getProperty(key));//通過鍵拿到值
        }
    }
    private static void mySave(Properties prop, String src) throws IOException {
        //將配置信息存儲(chǔ)到對(duì)象中
        prop.setProperty("USERNAME","root");
        prop.setProperty("PASSWORD","123456");
        prop.setProperty("DATABASE","YX2115");
        prop.setProperty("PORT","3306");
        //寫入文件
        FileWriter fw = new FileWriter(src);//創(chuàng)建輸出流對(duì)象
        prop.store(fw,"MyDataBase Configure!~");
        fw.close();
    }
}

8 -總結(jié)

本篇文章介紹了集合的常用方法以及個(gè)別集合的底層是如何實(shí)現(xiàn)的。介紹了集合的繼承與實(shí)現(xiàn)結(jié)構(gòu)。各個(gè)集合的擴(kuò)容方式及擴(kuò)容大小以及各個(gè)集合的優(yōu)點(diǎn)和用途。希望大家可以根據(jù)本篇文章可以更加深刻的理解java中的集合。

到此這篇關(guān)于java集合超詳細(xì)的文章就介紹到這了,更多相關(guān)java集合內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java環(huán)境下高德地圖Api的使用方式

    Java環(huán)境下高德地圖Api的使用方式

    這篇文章主要介紹了Java環(huán)境下高德地圖Api的使用方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • Spring實(shí)現(xiàn)HikariCP連接池的示例代碼

    Spring實(shí)現(xiàn)HikariCP連接池的示例代碼

    在SpringBoot 2.0中,我們使用默認(rèn)連接池是HikariCP,本文講一下HikariCP的具體使用,具有一定的參考價(jià)值,感興趣的可以了解一下
    2021-08-08
  • Redis Lettuce連接redis集群實(shí)現(xiàn)過程詳細(xì)講解

    Redis Lettuce連接redis集群實(shí)現(xiàn)過程詳細(xì)講解

    這篇文章主要介紹了Redis Lettuce連接redis集群實(shí)現(xiàn)過程,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧
    2023-01-01
  • Java Unsafe學(xué)習(xí)筆記分享

    Java Unsafe學(xué)習(xí)筆記分享

    今天小編就為大家分享一篇Java Unsafe學(xué)習(xí)筆記,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • Springboot整合nacos報(bào)錯(cuò)無法連接nacos的解決

    Springboot整合nacos報(bào)錯(cuò)無法連接nacos的解決

    這篇文章主要介紹了Springboot整合nacos報(bào)錯(cuò)無法連接nacos的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-06-06
  • 使用ScheduledThreadPoolExecutor踩過最痛的坑

    使用ScheduledThreadPoolExecutor踩過最痛的坑

    這篇文章主要介紹了使用ScheduledThreadPoolExecutor踩過最痛的坑及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-08-08
  • Java實(shí)現(xiàn)Floyd算法的示例代碼

    Java實(shí)現(xiàn)Floyd算法的示例代碼

    Floyd算法又稱為插點(diǎn)法,是一種利用動(dòng)態(tài)規(guī)劃的思想尋找給定的加權(quán)圖中多源點(diǎn)之間最短路徑的算法。本文將用Java語言實(shí)現(xiàn)Floyd算法,需要的可以參考一下
    2022-07-07
  • 如何將Java打開CSV文件到JTable展示

    如何將Java打開CSV文件到JTable展示

    本文主要介紹了如何將Java打開CSV文件到JTable展示,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-03-03
  • 解決Mybatis-plus和pagehelper依賴沖突的方法示例

    解決Mybatis-plus和pagehelper依賴沖突的方法示例

    這篇文章主要介紹了解決Mybatis-plus和pagehelper依賴沖突的方法示例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • Java使用自動(dòng)化部署工具Gradle中的任務(wù)設(shè)定教程

    Java使用自動(dòng)化部署工具Gradle中的任務(wù)設(shè)定教程

    Grandle使用同樣運(yùn)行于JVM上的Groovy語言編寫,本文會(huì)對(duì)此進(jìn)行初步夠用的講解,接下來我們就一起來看一下Java使用自動(dòng)化部署工具Gradle中的任務(wù)設(shè)定教程:
    2016-06-06

最新評(píng)論