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
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...