還在深入瞭解集合框架(ArrayList、LinkedList)原始碼?先看看這篇文章吧

偷得浮笙發表於2020-10-31

寫在前面,Java基礎系列文章都是作者基於b站尚矽谷的Java基礎視訊所做的筆記,沒有時間的同學可以認真看看,如果有時間的同學,還是建議看看視訊,畢竟筆記說到底還是自己的東西,每個人的習慣也是不一樣的,所以為了自己,學就對了,加油!
也請各位同學,如果感覺對自己有幫助,可以幫忙給個一鍵三連,謝謝!


1.Java集合框架概述

1.1 集合框架與陣列的對比和概述

/**
 * 一、集合框架的概述
 *
 * 1.集合、陣列都是對多個資料進行儲存操作的結構,簡稱Java容器。
 *  說明:此時的儲存,主要指的是記憶體層面的儲存,不涉及到持久化的儲存(.txt,.jpg,.avi 到資料庫中)
 *
 * 2.1 陣列在儲存多個資料方面的特點:
 *      > 一旦初始化以後,其長度就確定了。
 *      > 陣列一旦定義好,其元素的型別也就確定了。我們也就只能操作指定型別的資料了。
 *       比如:String[] arr; int[] arr1; Object[] arr2;
 * 2.2 陣列在儲存多個資料方面的缺點:
 *      > 一旦初始化以後,其長度就不可修改。
 *      > 陣列中提供的方法非常有限,
 *              對於新增、刪除、插入資料等操作,非常不便,同時效率不高。
 *      > 獲取陣列中實際元素的個數的需求,陣列沒有現成的屬性或方法可用
 *      > 陣列儲存資料的特點:有序、可重複。(對於無序、不可重複的需求,陣列不能滿足)
 *
 * 2.3 集合儲存的優點:解決陣列儲存資料方面的弊端
 */

1.2 集合的使用場景

在這裡插入圖片描述

image-20201027173617389

1.3 集合框架涉及到的API

Java 集合可分為CollectionMap 兩種體系

  • Collection介面單列資料,定義了存取一組物件的方法的集合
    • List元素有序可重複的集合
    • Set元素無序不可重複的集合
  • Map介面雙列資料,儲存具有對映關係“key-value鍵值對”的集合
  • Collection介面繼承樹

image-20201027174004944

  • Map介面繼承樹

image-20201027174038824

/**
 * 二、集合框架
 *   |----Collection介面:單列集合,用來儲存一個一個的物件
 *       |----List介面:儲存有序的、可重複的資料。  -->“動態”陣列
 *           |----ArrayList、LinkedList、Vector
 *
 *       |----Set介面:儲存無序的、不可重複的資料   -->高中講的“集合”
 *           |----HashSet、LinkedHashSet、TreeSet
 *
 *   |----Map介面:雙列集合,用來儲存一對(key - value)一對的資料   -->高中函式:y = f(x) (x對應key,y對應value)
 *           |----HashMap、LinkedHashMap、TreeMap、Hashtable、Properties
 */

2.Collection介面方法

  • Collection 介面是List、Set 和Queue 介面父介面,該介面裡定義的方法既可用於操作Set 集合,也可用於操作List 和Queue 集合。
  • JDK不提供此介面的任何直接實現,而是提供更具體的子介面(如:Set和List)實現。
  • 在Java5 之前,Java 集合會丟失容器中所有物件的資料型別,把所有物件都當成Object 型別處理;從JDK 5.0 增加了泛型以後,Java 集合可以記住容器中物件的資料型別

2.1 Collection介面中的常用方法1

  • 新增
    • add(Object obj)
    • addAll(Collection coll)
  • 獲取有效元素的個數
    • intsize( )
  • 清空集合
    • voidclear( )
  • 是否是空集合
    • boolean isEmpty( )
  • 是否包含某個元素
    • boolean contains(Object obj):是通過元素的equals方法來判斷是否是同一個物件
    • boolean containsAll(Collection c):也是呼叫元素的equals方法來比較的。拿兩個集合的元素挨個比較
  • 刪除
    • boolean remove(Object obj) :通過元素的equals方法判斷是否是要刪除的那個元素。只會刪除找到的第一個元素
    • boolean removeAll(Collection coll):取當前集合的差集
  • 取兩個集合的交集
    • boolean retainAll(Collection c):把交集的結果存在當前集合中,不影響c
  • 集合是否相等
    • boolean equals(Object obj)
  • 轉成物件陣列
    • Object[] toArray( )
  • 獲取集合物件的雜湊值
    • hashCode( )
  • 遍歷
    • iterator( ):返回迭代器物件,用於集合遍歷
/**
 * 三、Collection介面中方法的使用
 */
public class CollectionTest {

    @Test
    public void test1(){
        Collection coll = new ArrayList();

        //add(Object e):將元素e新增到集合coll中
        coll.add("AA");
        coll.add("BB");
        coll.add(123);//自動裝箱,將int型別包裝成Integer型別
        coll.add(new Date());

        //size():獲取新增的元素的個數
        System.out.println(coll.size());//4

        //addAll(Collection colls):將colls集合中的元素新增到當前的集合中
        Collection colls = new ArrayList();
        colls.add(456);
        colls.add("CC");
        coll.addAll(colls);

        System.out.println(coll.size());//6
        System.out.println(coll.toString());

        //clear():清空集合中的元素
        coll.clear();

        //isEmpty():判斷當前集合是否為空
        System.out.println(coll.isEmpty()); //true

        System.out.println("清空集合中的元素後:" + coll); //[]
    }

}

2.2 Collection介面中的常用方法2

Person類

public class Person {

    private String name;
    private int age;

    public Person() {
    }

    public Person(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 "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        System.out.println("Person equals()....");
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return age == person.age &&
                Objects.equals(name, person.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
}

測試類

/**
 * Collection介面中宣告的方法的測試
 *
 * contains(Object obj),如果要比較obj與集合中某個元素的"內容"是否相等,
 * 要求當前obj型別要重寫equals()方法,因為equals()比較的就是兩個物件的內容是否相等
 *
 * 結論:
 * 向Collection介面的實現類的物件中新增資料obj時,要求obj所在類要重寫equals()方法.
 */
public class CollectionTest {
    
    @Test
    public void test1(){
        Collection coll = new ArrayList();
        coll.add(123);
        coll.add(456);
//        Person p = new Person("Jerry",20);
//        coll.add(p);
        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); //true,Integer型別重寫了equals方法
        System.out.println(contains); //true
        System.out.println(coll.contains(new String("Tom")));//true,String類重寫了equals方法
//        System.out.println(coll.contains(p));//true
        //如果Person類重寫了equals()方法,則比較內容是否相等
        System.out.println(coll.contains(new Person("Jerry",20)));

        //2.containsAll(Collection colls):判斷形參colls中的所有元素是否都存在於當前集合中。
        Collection colls = Arrays.asList(123,4567);
        //判斷coll集合是否包含colls的所有元素
        System.out.println(coll.containsAll(colls)); //false
    }
}

2.3 Collection介面中的常用方法3

Person類

public class Person {

    private String name;
    private int age;

    public Person() {
    }

    public Person(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 "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        System.out.println("Person equals()....");
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return age == person.age &&
                Objects.equals(name, person.name);
    }

    @Override
    public int hashCode() {

        return Objects.hash(name, age);
    }
}

測試類

/**
 * Collection介面中宣告的方法的測試
 *
 * contains(Object obj),如果要比較obj與集合中某個元素的"內容"是否相等,
 * 則當前obj型別要重寫equals()方法,因為equals()比較的就是兩個物件的內容是否相等
 *
 * 結論:
 * 向Collection介面的實現類的物件中新增資料obj時,要求obj所在類要重寫equals()方法.
 */
public class CollectionTest {

    @Test
    public void test2(){
        //3.remove(Object obj):從當前集合中移除obj元素。
        Collection coll = new ArrayList();
        coll.add(123);
        coll.add(456);
        coll.add(new Person("Jerry",20));
        coll.add(new String("Tom"));
        coll.add(false);

        coll.remove(1234);
        System.out.println(coll);

        coll.remove(new Person("Jerry",20));
        System.out.println(coll);

        //4. removeAll(Collection coll1):差集:從當前集合中移除coll1中所有的元素。
        Collection coll1 = Arrays.asList(123,456);
        coll.removeAll(coll1);
        System.out.println(coll);

    }

    @Test
    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);

        //5.retainAll(Collection coll1):交集:獲取當前集合和coll1集合的交集,並返回給當前集合
//        Collection coll1 = Arrays.asList(123,456,789);
//        coll.retainAll(coll1);
//        System.out.println(coll); //123,456

        //6.equals(Object obj):要想返回true,需要當前集合和形參集合的元素都相同。
        Collection coll1 = new ArrayList();
        coll1.add(123);
        coll1.add(456);
        coll1.add(new Person("Jerry",20));
        coll1.add(new String("Tom"));
        coll1.add(false);

        System.out.println(coll.equals(coll1)); //true
    }

}

2.4 Collection介面中的常用方法4

Person類

public class Person {

    private String name;
    private int age;

    public Person() {
    }

    public Person(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 "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        System.out.println("Person equals()....");
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return age == person.age &&
                Objects.equals(name, person.name);
    }

    @Override
    public int hashCode() {

        return Objects.hash(name, age);
    }
}

測試類

/**
 * Collection介面中宣告的方法的測試
 *
 * contains(Object obj),如果要比較obj與集合中某個元素的"內容"是否相等,
 * 則當前obj型別要重寫equals()方法,因為equals()比較的就是兩個物件的內容是否相等
 *
 * 結論:
 * 向Collection介面的實現類的物件中新增資料obj時,要求obj所在類要重寫equals()方法.
 */
public class CollectionTest {

    @Test
    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);

        //7.hashCode():返回當前物件的雜湊值
        System.out.println(coll.hashCode());

        //8.集合 --->陣列: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中測試

    }
}

3.Iterator迭代器介面

  • Iterator物件稱為迭代器(設計模式的一種),主要用於遍歷Collection 集合中的元素
  • GOF給迭代器模式的定義為:提供一種方法訪問一個容器(container)物件中各個元素,而又無需暴露該物件的內部細節。迭代器模式,就是為容器而生。類似於“公交車上的售票員”、“火車上的乘務員”、“空姐”。
  • Collection介面繼承了java.lang.Iterable介面,該介面有一個iterator( )方法,那麼所有實現了Collection介面的集合類都有一個iterator( )方法,用於返回一個實現了Iterator介面的物件。
  • Iterator 僅用於遍歷集合,Iterator本身並不提供承裝物件的能力。如果需要建立Iterator 物件,則必須有一個被迭代的集合。
  • 集合物件每次呼叫iterator( )方法都得到一個全新的迭代器物件預設遊標都在集合的第一個元素之前

在這裡插入圖片描述

3.1 使用Iterator遍歷Collection

/**
 * 集合元素的遍歷操作,使用迭代器Iterator介面
 * 1.內部的方法:hasNext() 和  next()
 *            hasNext():沒有指標下移操作,只是判斷是否存在下一個元素
 *            next():指標下移,返回該指標所指向的元素
 * 2.集合物件每次呼叫iterator()方法都得到一個全新的迭代器物件,
 *      預設遊標都在集合的第一個元素之前。
 * 3.內部定義了remove(),可以在遍歷的時候,刪除集合中的元素。
 *      注意:此方法不同於集合直接呼叫remove()方法
 */
public class IteratorTest {

    @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);
        //建立迭代器物件
        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());
        }
    }
  
}

3.2 迭代器Iterator的執行原理

image-20201027180053021

3.3 Iterator遍歷集合的兩種錯誤寫法

/**
 * 集合元素的遍歷操作,使用迭代器Iterator介面
 * 1.內部的方法:hasNext() 和  next()
 *            hasNext():沒有指標下移操作,只是判斷是否存在下一個元素
 *            next():指標下移,返回該指標所指向的元素
 * 2.集合物件每次呼叫iterator()方法都得到一個全新的迭代器物件,
 *      預設遊標都在集合的第一個元素之前。
 * 3.內部定義了remove(),可以在遍歷的時候,刪除集合中的元素。
 *      注意:此方法不同於集合直接呼叫remove()方法
 */
public class IteratorTest {

    @Test
    public void test2(){

        Collection coll = new ArrayList();
        coll.add(123);
        coll.add(456);
        coll.add(new Person("Jerry",20));
        coll.add(new String("Tom"));
        coll.add(false);

        //錯誤方式一:會報NoSuchElementException異常
//        Iterator iterator = coll.iterator();
//        while((iterator.next()) != null){ 
//            System.out.println(iterator.next());
//        }

        //錯誤方式二:每次建立迭代器物件,指標就返回到第一個元素之前,使用while就會出現死迴圈
        //集合物件每次呼叫iterator()方法都得到一個全新的迭代器物件,
        // 預設遊標都在集合的第一個元素之前。
        while (coll.iterator().hasNext()){
            System.out.println(coll.iterator().next());
        }
    }

}

3.4 Iterator迭代器remove( )的使用

/**
 * 集合元素的遍歷操作,使用迭代器Iterator介面
 * 1.內部的方法:hasNext() 和  next()
 *            hasNext():沒有指標下移操作,只是判斷是否存在下一個元素
 *            next():指標下移,返回該指標所指向的元素
 * 2.集合物件每次呼叫iterator()方法都得到一個全新的迭代器物件,
 *      預設遊標都在集合的第一個元素之前。
 * 3.內部定義了remove(),可以在遍歷的時候,刪除集合中的元素。
 *      該方法移除的是iterator.next()方法最後訪問的元素
 *      注意:此方法不同於集合直接呼叫remove()方法
 */
public class IteratorTest {

    //測試Iterator中的remove()方法
    //如果還未呼叫next()或 在上一次呼叫 next 方法之後已經呼叫了 remove 方法,
    // 再呼叫remove都會報IllegalStateException。
    @Test
    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()){
            //如果還未呼叫next(),就已經呼叫了remove()方法,
            //會報IllegalStateException異常
//            iterator.remove();
            Object obj = iterator.next();
            if("Tom".equals(obj)){
                iterator.remove(); //刪除元素
            // 再次呼叫remove()方法,也會報IllegalStateException異常
//                iterator.remove();
            }
        }
        //遍歷集合
        //注意:上面的while迴圈結束後,指標已經指向了最後的位置,
        //需要重新建立一個iterator物件,從第一個元素之前的位置開始遍歷
        iterator = coll.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }
  
  	//使用Iterator迭代器刪除集合中的所有元素
    @Test
    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);

        System.out.println("未刪除元素之前:"+coll.size()); //5

        Iterator iterator = coll.iterator();
        while (iterator.hasNext()) {
            iterator.next();
            iterator.remove();
        }

        System.out.println("刪除元素之後:"+coll.size()); //0
    }	
  
}

注意:

  • Iterator可以刪除集合的元素,但是是遍歷過程中通過迭代器物件的remove( )方法,不是集合物件的remove方法。
  • 如果還未呼叫next( )或在上一次呼叫next方法之後已經呼叫了remove方法,再呼叫remove都會報IllegalStateException

3.5 新特性foreach迴圈遍歷集合或陣列

  • Java 5.0 提供了foreach迴圈迭代訪問Collection和陣列
  • 遍歷操作不需獲取Collection或陣列的長度,無需使用索引訪問元素。
  • 遍歷集合的底層呼叫Iterator完成操作
  • foreach還可以用來遍歷陣列

image-20201027180447640

/**
 * jdk 5.0 新增了foreach迴圈(增強for迴圈),用於遍歷集合、陣列
 */
public class ForTest {

    @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);

        //for(集合中元素的型別 區域性變數 : 集合物件)
        //內部仍然呼叫了迭代器。
        for(Object obj : coll){
            System.out.println(obj);
        }
    }

    @Test
    public void test2(){
        int[] arr = new int[]{1,2,3,4,5,6};
        //for(陣列元素的型別 區域性變數 : 陣列物件)
        for(int i : arr){
            System.out.println(i);
        }
    }

    //練習題
    //使用普通的for迴圈,賦值的都是原來的陣列的元素,
    //而使用增強for迴圈,賦值的是新的變數s,相當於把"GG"賦值給新的陣列s
    //所以原來的陣列元素保持不變
    @Test
    public void test3(){

        String[] arr = new String[]{"MM","MM","MM"};

//        //方式一:普通for迴圈的賦值操作
//        for(int i = 0;i < arr.length;i++){
//            arr[i] = "GG";
//        }

        //方式二:增強for迴圈的賦值操作
        //使用增強for迴圈,賦值的是新的變數s,相當於把"GG"賦值給新的陣列s
        for(String s : arr){
            s = "GG";
            System.out.println(s);
        }

        System.out.println("***************");

        for(int i = 0;i < arr.length;i++){
            System.out.println(arr[i]);
        }

    }
}

4.Collection子介面一:List介面

  • 鑑於Java中陣列用來儲存資料的侷限性,我們通常使用List替代陣列
  • List集合類中的元素有序且可重複,集合中的每個元素都有其對應的順序索引
  • List容器中的元素都對應一個整數型的序號記載其在容器中的位置,可以根據序號存取容器中的元素
  • JDK API中List介面實現類常用的有:ArrayListLinkedListVector

4.1 List介面常用實現類的對比

/**
 * 1. List介面框架
 *
 *  |----Collection介面:單列集合,用來儲存一個一個的物件
 *       |----List介面:儲存有序的、可重複的資料。  -->“動態”陣列,替換原有的陣列
 *           |----ArrayList:作為List介面的主要實現類;執行緒不安全的,效率高;底層使用Object[] elementData儲存
 *           |----LinkedList:對於頻繁的插入、刪除操作,使用此類效率比ArrayList高;底層使用雙向連結串列儲存
 *           |----Vector:作為List介面的古老實現類;執行緒安全的,效率低;底層使用Object[] elementData儲存
 */

4.2 ArrayList的原始碼分析

  • ArrayListList 介面典型實現類主要實現類
  • 本質上,ArrayList是物件引用的一個 “變長” 陣列
/**
 * 2. ArrayList的原始碼分析:
 *   2.1 jdk 7的情況下
 *      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)
 *
 *   2.2 jdk 8中ArrayList的變化:
 *      ArrayList list = new ArrayList();//底層Object[] elementData初始化為{}.並沒有建立長度為10的陣列
 *
 *      list.add(123);//第一次呼叫add()時,底層才建立了長度為10的陣列,並將資料123新增到elementData[0]
 *      ...
 *      後續的新增和擴容操作與jdk 7 無異。
 *
 *   2.3 小結:jdk7中的ArrayList物件的建立類似於單例的餓漢式,
 *   而jdk8中的ArrayList物件的建立類似於單例的懶漢式,延遲了陣列的建立,節省記憶體。
 */

4.3 LinkedList的原始碼分析

  • 對於頻繁的插入或刪除元素的操作,建議使用LinkedList類,效率較高
  • LinkedList雙向連結串列,內部沒有宣告陣列,而是定義了Node型別的firstlast,用於記錄首末元素。同時,定義內部類Node,作為LinkedList中儲存資料的基本結構。

image-20201027183646046

/**
 *  3. LinkedList的原始碼分析:
 *      LinkedList list = new LinkedList(); 內部宣告瞭Node型別的first和last屬性,預設值為null
 *      list.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;
 *             }
 *         }
 *
 */

4.4 Vector的原始碼分析

  • Vector 是一個古老的集合,JDK1.0就有了。大多數操作與ArrayList相同,區別之處在於Vector是執行緒安全的
  • 在各種list中,最好把ArrayList作為預設選擇當插入、刪除頻繁時,使用LinkedList;Vector總是比ArrayList慢,所以儘量避免使用。
/**
 *   4. Vector的原始碼分析:jdk7和jdk8中通過Vector()構造器建立物件時,
 *    底層都建立了長度為10的陣列。在擴容方面,預設擴容為原來陣列長度的2倍。
 */

4.5 List介面中的常用方法測試

List除了從Collection集合繼承的方法外,List 集合裡新增了一些根據索引來操作集合元素的方法。

  • void add(intindex, 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位置的子集合
/**
 *   5. List介面中的常用方法
 */
public class ListTest {

    /**
     * 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迴圈
     *                      ③ 普通的迴圈
     */
    @Test
    public void test3(){
        ArrayList list = new ArrayList();
        list.add(123);
        list.add(456);
        list.add("AA");

        //方式一:Iterator迭代器方式
        Iterator iterator = list.iterator();
        while(iterator.hasNext()){
            System.out.println(iterator.next());
        }

        System.out.println("***************");

        //方式二:增強for迴圈
        for(Object obj : list){
            System.out.println(obj);
        }

        System.out.println("***************");

        //方式三:普通for迴圈
        for(int i = 0;i < list.size();i++){
            System.out.println(list.get(i));
        }

    }

    @Test
    public void test2(){
        ArrayList list = new ArrayList();
        list.add(123);
        list.add(456);
        list.add("AA");
        list.add(new Person("Tom",12));
        list.add(456);
        //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); //[2,4),左閉右開
        System.out.println(subList);
        System.out.println(list);
    }

    @Test
    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);

        //void add(int index, Object ele):在index位置插入ele元素
        list.add(1,"BB");
        System.out.println(list);

        //boolean addAll(int index, Collection eles):從index位置開始將eles中的所有元素新增進來
        List list1 = Arrays.asList(1, 2, 3);
        list.addAll(list1);
//        list.add(list1); //相當於把list1看成一個整體,新增到list集合中
        System.out.println(list.size());//9

        //Object get(int index):獲取指定index位置的元素
        System.out.println(list.get(0)); //獲取第一個位置的元素

    }

}

4.6 有關List的面試題

面試題一

請問ArrayList / LinkedList / Vector 的異同?談談你的理解?ArrayList的底層是什麼?擴容機制?Vector 和 ArrayList的最大區別?

   /**
     * 請問ArrayList/LinkedList/Vector的異同?談談你的理解?
     * ArrayList底層是什麼?擴容機制?Vector和ArrayList的最大區別?
     * 
     * 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。
     */

面試題二

/**
    List面試題
 */
public class ListExer {
    /*
    區分List中remove(int index)和remove(Object obj)
     */
    @Test
    public void testListRemove() {
        List list = new ArrayList();
        list.add(1);
        list.add(2);
        list.add(3);
        System.out.println("原來的集合元素:" + list);
        updateList(list);
        System.out.println(list);
    }

    private void updateList(List list) {
//        list.remove(2); //刪除索引是2的元素
        list.remove(new Integer(2)); //刪除元素是2的元素
    }

}

相關文章