菜鳥學JAVA之——集合框架(一)(List接口的實現類ArrayList)

集合框架

接下來將要學習的內容爲:

	1.Collection接口(線性存儲)(容器的最高父接口)

​		a)List接口(有序(指有下標/索引)、數據可重複)

​		b)Set接口(無序,數據不可重複)
	
​		c)queue隊列

	2.Map接口(鍵(key)-值(value)對存儲)(映射關係)

首先了解一個設計模式:適配者模式(通俗的理解是功能基本不變,只是改了方法名)(最主要的功能就是將一個接口轉換爲另一個接口)

List接口的實現類:

  1. ArrayList(底層爲數組結構)

    在數組中賦值方式爲a[0] = 1; ArrayList底層還是數組,數組賦值是通過腳標賦值的,我現在還要用他賦值的功能,但是對外提供接口變了,賦值變爲了add();

    ​ 優點:查、改效率高

    2.LinkedList(底層爲雙向鏈表)

    ​ 優點:增、刪效率高

    ​3.Vector(和ArraysList基本上一樣(數組結構),只不過他是線程安全的,訪問效率低)

自己實現容器就需要實現Collection接口,並且實現所有需要實現的方法。Collection沒有get()方法,所以不能定位。它也沒有set()方法。但List裏面有這兩個方法

ArrayList

ArrayList 無參的構造方法,創建了一個長度爲0的數組

ArrayList list = new ArrayList();//默認容量爲0

也有有參的構造方法,指定了初始大小

本質上就是創建了一個參數大小的數組

ArraysList list = new ArrayList(10);//容量設置爲10
//還可以傳一個集合,將傳進的集合中的元素copy給新集合

來看看源碼

public ArrayList(int initialCapacity) {  //創建時可傳參
        if (initialCapacity > 0) {  //如果傳的參數容量大於0
            this.elementData = new Object[initialCapacity];  //創建一個大小爲initialCapacity的數組
        } else if (initialCapacity == 0) {
            this.elementData = EMPTY_ELEMENTDATA; //如果傳入的參數爲0,那就是默認的那個空數組
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+  //如果參數小於0則拋出一個異常
                                               initialCapacity);
        }
    }

1.添加元素(add())

添加過程:

  1. 先將底層數組擴容
  2. 將元素賦值到數組對應位置
  3. 返回true
list.add(10);//這裏的這個10是基礎數據類型的對象類型:Integer類型

list.add("abc")//添加元素的位置跟add的次序有關,第一個add在數組的第一個位置

源碼

 public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e; //核心代碼:把這個元素賦給了數組相應位置。
        return true; //添加成功,返回一個true。如果添加不成功在上一行代碼中就會報錯,不會執行到這一行
    }
//這就是適配者模式,把給數組賦值的功能的名稱轉爲了add,外面添加元素調用add方法就行了,功能沒有變

add還可以給指定位置添加元素

//爲指定位置添加元素   第一個參數:指定位置,第二個參數:元素值
add(index,data);//給index位置添加data數據,其他數據會往後擠

注意:

  • 只能向前面有數據的位置插入,不能中間空了好多位置向後插入,比如容量大小爲10,目前只有兩個元素,則只能往0,1,2的位置插入,不能向3,4,5…等位置隔着插入
  • ArrayList對象不能存儲基本類型,只能存儲引用類型的數據。類似 不能寫,但是存儲基本數據類型對應的包裝類型是可以的。所以,想要存儲基本類型數據, <> 中的數據類型,必須轉換後才能編寫。

2.獲取元素(get())

list.get(0);

源碼

//get 
public E get(int index) {
        rangeCheck(index);
        return elementData(index);//如果上句不拋異常,則執行到這句,返回相應的元素
    }

//rangeCheck()
private void rangeCheck(int index) {
        if (index >= size)  //如果腳標大於size則拋異常
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }
//elementData()
E elementData(int index) {
        return (E) elementData[index];//返回數組相應腳標位置的元素
    }
//適配者模式把上面的取值過程轉換爲了一個方法名get()

大家注意一下上面的爲什麼要用index跟size比較而不用index跟elementData.length?(elementData就是我們存數據的數組)

答:size記錄的是現在集合中的元素個數,而elementData.length獲取到的是數組的長度。如果我指定初始容量爲100,而只添加了兩個元素。用elementData.length獲取到的是100,但容量裏面只有兩個數據是有效的,所以存幾個只能取幾個。所以自己在寫底層實現時也要有一個變量來記錄數據的個數,因爲初始數組大小不準。

如果是數組的話,獲取沒放過元素的位置,返回的是默認值。而arraylist的get方法就會報錯

獲取元素個數:size()方法(數組中獲取長度是length,String獲取長度是length())

3.修改元素(set())

返回值爲修改之前的值

list.set(0,"first");//注意他修改後會返回原來的數據 

4.刪除元素(remove())

按照下標刪返回刪除之前的元素;按照元素刪除,返回布爾值。

list.remove(int index);//按下標刪除,返回值是刪之前的元素
list.remove(Object o);//按內容刪,返回一個布爾值,刪成功或刪失敗
//刪除一個元素後,後面的元素統一前移

注意:如果元素爲整數,remove的參數爲int,按照下標刪除;參數爲Integer,按照元素刪除

list.remove(3);//按腳標刪
list.remove(new Integer(3));//按元素刪,注意存入的基礎數據類型元素默認是它的對象類型的

如果容器中有多個3,remove一次,刪除的是第一個3

ArrayList的遍歷

ArrayList<String> list = new ArrayList<>();//指定容器寸的內容必須是String的(泛型的一個特點,編譯時就把類型確定了)
//1.8版本之前,後面的<>裏面需要加類型,
//1.8版本之後 可以不用加,因爲1.8版本之後加入了語法糖,可以進行類型推斷
//泛型不支持基本數據類型只支持對象數據類型

list.add("aa");
list.add("bb");
list.add("cc");
list.add("dd");
//遍歷ArrayList
for(int i = 0; i < list.size(); i++) {
    System.out.println(list.get(i));
}
//迭代器:將Collection集合的遍歷統一起來,迭代器一開始指向空null
        Iterator<String> iterator = list.iterator();//注意不是new
/*
        //判斷是否有下一個元素,並沒有獲取它的值,而是他的內存地址,如果內存地址都沒有,則值一定沒有
        boolean hasNext = iterator.hasNext();
        //如果有,返回true,如果沒有,返回false
        System.out.println(hasNext);
        //過去下一個元素
        iterator.next();
*/

 while (iterator.hasNext()) {
                String e = iterator.next();
     			// 刪除當前迭代到的對象
     			//iterator.remove(); 輸出還會是原來的那些元素,這裏是爲了不影響迭代的過程(如果刪除了第一個元素,後面的元素會往前擠),但實際上這個元素確實被刪了,不信你試試輸出size()
                System.out.println(e);
            }

只有實現Itreable接口才可以使用增強for循環,他的底層就是用迭代器實現的

Iterator只需要記住hasNext()、next()、remove()即可
注:

  • 通過迭代器刪除元素,不會影響整個遍歷過程
  • 迭代完成後,迭代器的指針就會指向最後一個元素,所以要想再次遍歷就需要重新過去迭代器對象

list集合的迭代器

ArrayList<String> list = new ArrayList<>();
list.add("aa");
list.add("bb");
list.add("cc");
list.add("dd");
ListIterator<String> listIterator = list.listIterator();
//從上向下
 while (listIterator.hasNext()) {
            System.out.println(listIterator.next());
        }
//從下向上
while (listIterator.hasPrevious()) {
            System.out.println(listIterator.previous());
        }
//listIterator獨有的方法
//添加元素
listIterator.add("e");
//獲取上一個元素的下標
listIterator.previousIndex();
//獲取下一個元素的下標
listIterator.nextIndex();

Iterator只能從上往下找(相當於單鏈表),ListIterator的特點是既能從上往下找,也能從下往上找。(相當於雙向鏈表)

兩個集合關係的方法

集合的一些方法

ArrayList<String> list = new ArrayList<>();
        list.add("aa");
        list.add("bb");
        list.add("bb");
        list.add("dd");
        list.add("ee");
        list.add("ff"); 
//根據元素獲取下標,第一次出現時的下標,  -1表示該元素不存在
        System.out.println(list.indexOf("aa"));//輸出0
        System.out.println(list.indexOf("h"));//輸出-1
        System.out.println(list.indexOf("bb"));//輸出1
        //最後一次出現的位置,比如獲取某個人的最後一次登錄時間
        System.out.println(list.lastIndexOf("bb"));//輸出2
        //判斷是否包含某個元素
        System.out.println(list.contains("a"));//其實index方法就包含了這個功能,他的底層實現用的就是indexOf
        //是否爲空,即size()是不是爲0。返回true爲空
        list.isEmpty();
        //刪除集合中的所有元素
        list.clear();

集合求子集,兩集合求合集、差集、交集

ArrayList<String> list = new ArrayList<>();
        list.add("aa");
        list.add("bb");
        list.add("bb");
        list.add("cc");
        list.add("dd");
        list.add("ee");

ArrayList<String> list2 = new ArrayList<>();
        list2.add("aa");
        list2.add("bb");
        list2.add("bb");
        list2.add("cc");
        list2.add("ff");
        list2.add("gg");
        /*
            子集
            第一個參數:起始下標(包含)
            第二個參數:結束下標(不包含)
         */
        List<String> list1 = list.subList(1,3);  //父類引用子類對象
        System.out.println(list1);
        //stulist不能單獨使用,他是定義在ArrayList裏的內部類(且他是私有的,只能由外部類使用),就比如有一個私有成員變量age,如果你都沒這個對象了,那這個age也就不存在了

        /*
        //求合集  將參數集合中的所有元素都添加到調用方法的集合中
        //參數傳的是集合,返回值是布爾型
        list.addAll(list2);
        System.out.println(list);
         */

        /*
        //求差集:將list中 list合list1的交集刪除
        //參數傳的是集合,返回值是布爾型
        //這裏注意一下:如果list2裏只有一個dd元素,而list裏有多個dd元素,則list裏所有的dd都會被刪除
        list.removeAll(list2);
        System.out.println(list);
         */

        //求交集
        list.retainAll(list2);
        System.out.println(list);

subList源碼

public List<E> subList(int fromIndex, int toIndex) {
        subListRangeCheck(fromIndex, toIndex, size);//先檢查範圍是否正常
        return new SubList(this, 0, fromIndex, toIndex);//當上面不拋異常才返回
    }

static void subListRangeCheck(int fromIndex, int toIndex, int size) {
        if (fromIndex < 0)
            throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
        if (toIndex > size)
            throw new IndexOutOfBoundsException("toIndex = " + toIndex);
        if (fromIndex > toIndex)
            throw new IllegalArgumentException("fromIndex(" + fromIndex +
                                               ") > toIndex(" + toIndex + ")");
    }

數組和集合的轉換

1.集合轉數組

list.toArray(),他不靈活,返回值是Object

toArray有個可傳參的方法,他是泛型方法,傳進的參數是什麼類型的它就返回什麼類型<T> T[] toArray(T[] a);
eg:


        List<String>  list1 = new ArrayList<>();
        list1.add("a");
        list1.add("b");
        list1.add("c");
        Object[] objectArray  = list1.toArray();
 
        
        List<String> list2= new ArrayList<>();
        list2.add("A");
        list2.add("B");
        list2.add("C");
        String[] strArray= list2.toArray(new String[list2.size()]);

2.數組轉集合

int[] array_int = {1,2,3};
//asList:如果參數爲基本數據類型數組,將整個數組作爲集合的一個元素。如果是對象類型的數組,將數組中的元素轉換到集合中
List list = Arrays.asList(array_int); //將會輸出數組首元素的內存地址

Integer[] array_integer = {1,2,3};//這些元素就是一個一個的Integer對象
Arrays.asList(array_integer);//這樣就將元素一個一個的放進了集合中
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章