JAVA中的ArrayList

来源:http://www.cnblogs.com/chenpi/archive/2016/03/06/5247946.html
-Advertisement-
Play Games

各種原因,前兩年做C語言去了,現在重新做JAVA, 感覺自己基礎很不扎實,要好好學習啦, 先從簡單的開始~ 以下內容基於jdk1.7.0_79源碼; 什麼是ArrayList 可以簡單的認為是一個動態數組;實際上ArrayList就是用數組實現的,長度不夠時,調用Arrays.copyOf方法,拷貝


各種原因,前兩年做C語言去了,現在重新做JAVA, 感覺自己基礎很不扎實,要好好學習啦, 先從簡單的開始~

以下內容基於jdk1.7.0_79源碼;

什麼是ArrayList

可以簡單的認為是一個動態數組;實際上ArrayList就是用數組實現的,長度不夠時,調用Arrays.copyOf方法,拷貝當前數組到一個新的長度更大的數組;

ArrayList特點

隨機訪問速度快,插入和移除性能較差(數組的特點);

支持null元素;

有順序;

元素可以重覆;

線程不安全;

ArrayList繼承的類和實現的介面

如下圖,是與ArrayList相關的介面和類,下麵將一一介紹各個介面和類中的方法;

PS:ArrayList中的方法主要是由Collection介面和List介面定義的;

Iterable介面

實現此介面以便支持foreach語法,如下代碼,ArrayList可以直接使用foreach語句遍歷元素:

package com.pichen.basis.col;

import java.util.ArrayList;
import java.util.List;

public class Main {

    public static void main(String[] args) {
        List<Integer> list = new ArrayList<Integer>();
        for(int i = 0; i < 10; i++){
            list.add(i);
        }
        
        //foreach語法
        for(Integer i : list){
            System.out.print(i.toString() + " ");
        }
        
    }
}
View Code

Collection介面

int size()方法:

返回集合的大小,在ArrayList類中有一個int類型的size私有屬性,當調用size方法時,直接返回該屬性;

boolean isEmpty()方法:

判斷集合是否為空,在ArrayList中,通過判斷size == 0來判斷集合是否為空;

boolean contains(Object o)方法:

判斷集合是否含有對象o,在ArrayList中,通過判斷indexOf(o) >= 0來判斷是否含有o對象;

查看indexOf(o)方法,代碼如下,主要功能是返回元素第一次出現時的下標索引,所以當下標索引大於等於0時,表示集合中存在該元素:

    public int indexOf(Object o) {
        if (o == null) {
            for (int i = 0; i < size; i++)
                if (elementData[i]==null)
                    return i;
        } else {
            for (int i = 0; i < size; i++)
                if (o.equals(elementData[i]))
                    return i;
        }
        return -1;
    }

註意這裡的相等判斷,調用的是o對象的equals方法,所以在調用contains方法時,要特別關註集合中對象的equals方法,是否有被重寫過,如Integer、String的equals方法是被重寫過的,一般我們自己定義的對象,如果沒重寫equals的話,預設調用的是Object的equals方法,舉個例子,看一下就明白了:

package com.pichen.basis.col;

import java.util.ArrayList;
import java.util.List;

class Dog{
}
public class ContainsTest {

    public static void main(String[] args) {
        List<Dog> dogList = new ArrayList<Dog>();
        Dog dog1 = new Dog();
        Dog dog2 = new Dog();
        dogList.add(dog1);
        System.out.println(dogList.contains(dog2));//false
        
        List<String> strList = new ArrayList<String>(); 
        strList.add("teststr");
        
        String str = new String("teststr");
        System.out.println(strList.contains(str));//true
        
    }

}
View Code

Iterator<E> iterator()方法:

返回一個迭代器對象,用於遍歷集合,事實上,ArrayList類里有兩個內部類ArrayList.Itr和ArrayList.ListItr,分別對應Iterator迭代器和ListIterator迭代器,後者比前者功能更加強大;從ArrayList.ListItr繼承自ArrayList.Itr就可以看出來,ListIterator迭代器支持更多的操作,如判斷前面還有沒有元素,即hasPrevious()方法,等;

Object[] toArray()方法:

將集合ArrayList轉換成Object數組,有時候需要用到數組的一些api時,可以使用該方法,註意返回的結果是Object類型的數組,如果想返回指定類型的數組,可以使用以下方法,<T> T[] toArray(T[] a);

<T> T[] toArray(T[] a)方法:

集合轉數組,返回指定類型的數組,註意入參T[] a需要指定數組存儲的空間,返回值為指定類型的數組;舉個例子,假如有一個Integer類型的集合,如果想把它轉換成Integer類型的數組,可以這樣寫:Integer[] arr = list.toArray(new Integer[list.size()]);

boolean add(E e)方法:

在集合最後面增加一個元素,在ArrayList中,其實現就是在其內部數組後面增加一個元素,不過要先保證內部數組長度足夠,如下代碼:

    public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }

boolean remove(Object o)方法:

在集合中移除對象o,在ArrayList中,其實現較add方法複雜,涉及空對象判斷,equals比較,數組移動等,性能相對較差;

boolean containsAll(Collection<?> c)方法:

判斷是否包含集合c中的所有元素,在ArrayList中,其實現方法是遍歷集合c中的每一個元素,調用contains方法,判斷集合是否包含該元素,只要有一個不包含就返回false,如下代碼:

    public boolean containsAll(Collection<?> c) {
        for (Object e : c)
            if (!contains(e))
                return false;
        return true;
    }

boolean addAll(Collection<? extends E> c)方法:

將集合c中的所有元素加到目標集合中去,在ArrayList中,其實現是先將集合c轉換成數組,然後通過數組拷貝實現;

boolean removeAll(Collection<?> c)方法:

移除目標集合中含有‘集合c中元素’的所有元素,在ArrayList中,最終還是操作數組,性能相對較差;

boolean retainAll(Collection<?> c)方法:

移除目標集合中‘不包含集合c中元素’的所有元素,在ArrayList中removeAll方法和retainAll方法都是通過調用ArrayList的batchRemove方法來實現的,後續詳細瞭解該方法的實現;

void clear()方法:

移除目標集合中的所有元素,在ArrayList中,就是將其內部數組所有元素賦null;

boolean equals(Object o)和int hashCode()方法

在ArrayLisy中,上面兩個方法都被重寫,equals方法依次取出集合中的所有元素進行比較,通過元素的equals方法,判斷是否相等,全部相等返回true;

hashCode方法的計算是通過所有元素的hashCode計算得到;順便說下hashcode,在java中隨處可見,一般用在HashMap, Hashtable, HashSet等等中,可用於減少equals方法的調用,快速訪問元素等,其實就是散列表的概念,如比較元素先比較其hashcode,如果hashcode不相等,那麼這兩個元素肯定不相等,也就不用調用其equals方法了;

demo代碼:以上方法的簡單使用

package com.pichen.basis.col;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

public class Test {

    public static void main(String[] args) {
        List<Integer> list = new ArrayList<Integer>();
        for(int i = 0; i < 10; i++){
            list.add(i);
        }
        
        //直接列印
        System.out.println(list.toString());
        
        //size()
        System.out.println(list.size());
        
        //contains
        System.out.println(list.contains(2));
        
        //iterator
        Iterator<Integer> iterator = list.iterator();
        while(iterator.hasNext()){
            System.out.print(iterator.next() + " ");
        }
        
        //toArray
        Object[] objArr = list.toArray();
        Integer[] intArr = list.toArray(new Integer[list.size()]);
        System.out.println("\n" + list.toArray());
        
        //add
        list.add(5);
        
        //remove
        list.remove(5);
        
        System.out.println(list);
        
        //containsAll
        System.out.println(list.containsAll(Arrays.asList(5,6)));
        
        //addAll
        list.addAll(Arrays.asList(555,666));
        System.out.println(list);
        
        //removeAll
        list.removeAll(Arrays.asList(555,666));
        System.out.println(list);
        
        //clear
        list.clear();
        System.out.println(list);
        
    }
}
View Code

List介面

除了Collection中定義的方法為,該介面增加了以下方法

boolean addAll(int index, Collection<? extends E> c);

在ArrayList中,該方法是在指定位置處增加一個集合中的所有元素,該操作涉及數組移動;

E get(int index);

返回下標為index的元素;

E set(int index, E element);

改變下標為index的元素的值

void add(int index, E element);

在下標為index的地方插入元素element,該操作涉及數組移動;

E remove(int index);

移除下標為index的元素,該操作涉及數組移動;

int indexOf(Object o);

返回元素o的最小下標,通過調用o的equals方法與集合中的元素進行比較;

int lastIndexOf(Object o);

返回元素o的最大下標,通過調用o的equals方法與集合中的元素進行比較;

ListIterator<E> listIterator();

返回listIterator迭代器,該迭代器支持向前操作;

ListIterator<E> listIterator(int index);

返回listIterator迭代器,從特定的位置開始,該迭代器支持向前操作;

List<E> subList(int fromIndex, int toIndex);

返回下標在fromIndex和toIndex之間的元素集合;

demo代碼:以上方法的簡單使用:

package com.pichen.basis.col;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.ListIterator;

public class Main {

    public static void main(String[] args) {
        List<Integer> list = new ArrayList<Integer>();
        for(int i = 0; i < 10; i++){
            list.add(i);
        }
        
        System.out.println(list);
        
        //addAll方法
        list.addAll(5, Arrays.asList(666,666, 6));
        System.out.println(list);
        
        //get方法
        System.out.println(list.get(5));
        
        //set方法
        list.set(5, 55);
        System.out.println(list.get(5));
        
        //add方法
        list.add(0, 555);
        System.out.println(list);
        
        //remove方法
        list.remove(0);
        System.out.println(list);
        
        //indexof方法
        System.out.println(list.indexOf(6));
        
        //lastIndexOf方法
        System.out.println(list.lastIndexOf(6));
        
        //listIterator方法
        ListIterator<Integer> listIterator = list.listIterator();
        System.out.println(listIterator.hasPrevious());
        
        //listIterator(index)方法
        ListIterator<Integer> iListIterator = list.listIterator(5);
        System.out.println(iListIterator.previous());
        
        //subList方法
        System.out.println(list.subList(5, 7));
    }
}
View Code

RandomAccess, Cloneable, java.io.Serializable介面

這三個介面是標識介面,裡面都是空的;

RandomAccess標識其支持快速隨機訪問;

Cloneable標識其支持對象複製;

Serializable標識其可序列化;

AbstractCollection類

大部分方法前面已經說明過了,不過該類下的contains方法、toArray方法等,遍歷的時候都是使用更加通用的迭代器方式進行遍歷;

AbstractList類

大部分方法前面已經說明過了,不過該類中有兩個私有內部類Itr和ListItr,對應的分別是兩個迭代器;

ArrayList類

ArrayList的具體實現

成員屬性:

private static final int DEFAULT_CAPACITY = 10;//初始容量

private static final Object[] EMPTY_ELEMENTDATA = {};//空ArrayList實例共用的一個空數組

private transient Object[] elementData; //真正存儲ArrayList中的元素的數組;

private int size;//存儲ArrayList的大小,註意不是elementData的長度

 

 除了其父介面定義的方法外,該類增加了以下方法

public ArrayList(int initialCapacity):

構造函數,指定初始大小

public ArrayList()

構造函數,使用共用的EMPTY_ELEMENTDATA空數組

public ArrayList(Collection<? extends E> c)

構造函數,通過集合初始化ArrayList

public void trimToSize()

節省空間用的,ArrayList是通過數組實現的,大小不夠時,增加數組長度,有可能出現數組長度大於ArrayList的size情況;

public void ensureCapacity(int minCapacity)

保證ArrayList能容納minCapacity個元素;

私有方法

ArrayList遍歷

一般工作中用的比較多的是遍歷操作,ArrayList支持三種方式

  • for迴圈下標遍歷;
  • 迭代器(Iterator和ListIterator);
  • foreach語句。
package com.pichen.basis.col;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;

public class Test {

    public static void main(String[] args) {
        List<Integer> list = new ArrayList<Integer>();
        for(int i = 0; i < 10; i++){
            list.add(i);
        }
        
        //直接列印
        System.out.println(list.toString());
        
        //for迴圈
        System.out.println("for迴圈:");
        for(int i = 0; i < list.size(); i++){
            System.out.print(list.get(i) + " ");
        }
        
        //foreach
        System.out.println("\nforeach:");
        for(Integer i : list){
            System.out.print(i + " ");
        }
        
        //iterator
        System.out.println("\niterator:");
        Iterator<Integer> iterator = list.iterator();
        while(iterator.hasNext()){
            System.out.print(iterator.next() + " ");
        }
        
        //listIterator
        System.out.println("\nlistIterator:");
        ListIterator<Integer> listIterator = list.listIterator();
        while(listIterator.hasNext()){
            System.out.print(listIterator.next() + " ");
        }
        System.out.println();
        while(listIterator.hasPrevious()){
            System.out.print(listIterator.previous() + " ");
        }
    }
}

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • //============================================================================ // Name : BubbleSort.cpp // Author : fffff // Version : // Copyright :
  • 1 /* 遍歷二叉樹就是以一定的規則將二叉樹中的節點排列成一個線性 2 * 序列,從而得到二叉樹節點的各種遍歷序列,其實質是:對一個 3 * 非線性的結構進行線性化。使得在這個訪問序列中每一個節點都 4 * 有一個直接前驅和直接後繼。 5 * 傳統的鏈式結構只能體現一種父子關係,¥不能直接得到節點在
  • 主要用於Web服務日誌最新行查看。 package main import( "fmt" "os" "bytes") const ( defaultBufSize = 4096) func tail( filename string, n int ) (lines []string,err erro
  • 文件操作介面類: package com.souvc.util.test; import java.io.File; public interface MyFileUtil { /** * 方法名:createDefaultFolder</br> * 詳述:創建預設文件夾-重覆的時候 會自動給文件命
  • const在C++中很常用,在編程中也建議多使用const去告訴編譯器和其他程式員某個值應該保持不變。 const可以用在很多地方: (1)用在classes外部修飾global或namespace作用域中的常量 (2)修飾文件、函數、或區塊作用域中被聲明為static的對象 (3)修飾classe
  • 「C語言」「例題」指針與鏈表
  • 變數: Python 是動態類型語言, 也就是說不需要預先聲明變數的類型。變數是對象的引用,變數只是將指針指向了對象所在的記憶體地址。變數的類型和值在賦值那一刻被初始化。 變數起名: 1.顯式-->通俗易懂 2.nums_of_alex_gf = 19 3.NumsOfAlexGf = 20 駝峰寫法
  • 匹配電子郵箱正則匹配表達式: /^[a-z]([a-z0-9]*[-_]?[a-z0-9]+)*@([a-z0-9]*[-_]?[a-z0-9]+)+[\.][a-z]{2,3}([\.][a-z]{2})?$/i 國際功能變數名稱格式如下:功能變數名稱由各國文字的特定字元集、英文字母、數字及“-”(即連字元或減號
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...