java集合----collection接口

java集合----collection接口


引入

面嚮對象語言對事物的體現都是以對象的形式,爲了方便對多個對象的操作,就要對對象進行存儲。 而Java 集合就像一種容器,可以動態地 把多個對象的引用放入容器中。另外一方面,使用 Array 存儲對象方面具有 一些弊端 。
比如:

  • 數組初始化以後,長度就不可變了,不便於擴展;

  • 數組中提供的屬性和方法少,不便於進行添加、刪除、插入等操作, 且效率 不 高。
    同時無法直接獲取存儲元素的個數;

  • 數組存儲的數據是有序的、可以重複的。 存儲數據的特點單一;

在java中集合框架主要分爲Collection和Map兩種體系.
在這裏插入圖片描述
這裏主要講解有關於Collection的一些操作。

Collection接口

Collection 接口是 List 、Set 和 Queue 接口的父接口,該接口裏定義的方法既可用於操作 Set 集合,也可用於操作 List 和 Queue 集合。
這裏可以看看在Java8中關於Collection接口的介紹:
在這裏插入圖片描述
翻譯爲:集合層次結構中的根接口。集合表示一組對象,稱爲其元素。有些集合允許複製元素,有些則不允許。有些是有序的,有些是無序的。JDK沒有提供該接口的任何直接實現:它提供了更具體的子接口(如SetList)的實現。此接口通常用於在需要最大通用性的地方傳遞和操作集合。

Collection接口的方法

  • add(T e): 添加一個元素(這裏T表示泛型的意思)
    例子:
    這裏代碼只給出了測試單元,可以看見Colletion接口add方法既可以添加int型,String型,還可以是個對象(這裏Person是我創建的一個對象)
public void test1() {
        Collection obj = new ArrayList();
        obj.add(123);
        obj.add("AA");
        obj.add(new Person("LC",20));
        Iterator iterator = obj.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
    }

結果:
在這裏插入圖片描述

  • addAll(Collection c ): 將指定的對象的集合加到當前集合中
    例如:
	@Test
    public void test1() {
        Collection obj = new ArrayList();
        //將數組元素轉化爲list列表
        Collection obj2 = Arrays.asList("123",132);
        obj.add(123);
        obj.add("AA");
        obj.add(new Person("LC",20));
        obj.addAll(obj2);
        Iterator iterator = obj.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
    }

結果:
在這裏插入圖片描述

  • int size() : 獲取有效元素的個數

例如:這裏使用size方法去返回obj中的元素個數

@Test
public void test2(){
        Collection obj = new ArrayList();
        obj.add(123);
        obj.add("AA");
        System.out.println(obj.size());
    }

結果:在這裏插入圖片描述
-void clear():清空集合

例如:使用clear方法後,我們再看看obj的size是多少

@Test
public void test2(){
        Collection obj = new ArrayList();
        obj.add(123);
        obj.add("AA");
        obj.clear();
        System.out.println(obj.size());
    }

結果,毋庸置疑的是0:
在這裏插入圖片描述

  • boolean isEmpty(): 判斷是否是空集合
    例如:
 	@Test
    public void test2(){
        Collection obj = new ArrayList();
        obj.add(123);
        obj.add("AA");
        boolean empty = obj.isEmpty();
        System.out.println(empty);
    }

結果:
在這裏插入圖片描述

  • boolean contains(Object obj): 是通過元素的 equals 方法來判斷是否是同一個對象
    例如:
	@Test
    public void test2(){
        Collection obj = new ArrayList();
        obj.add(123);
        obj.add("AA");
        boolean contains = obj.contains(123);
        System.out.println(contains);
    }

結果:
在這裏插入圖片描述

  • boolean containsAll(Collection c) 也是調用元素的 equals 方法來比較的 。拿兩個集合的元素挨個比較 。
    例如:
	@Test
    public void test2(){
        Collection obj = new ArrayList();
        Collection obj2 =  Arrays.asList(123);
        obj.add(123);
        obj.add("AA");
        boolean containsAll = obj.containsAll(obj2);
        System.out.println(containsAll);
    }

結果:
在這裏插入圖片描述

  • boolean remove(Object obj) 通過 元素的 equals 方法判斷是否是要刪除的那個元素 。 只會刪除找到的第一個元素。
    例如:
	@Test
    public void test3(){
        Collection obj = new ArrayList();
        obj.add(123);
        obj.add(123);
        obj.add("AA");
        obj.add("BB");
        obj.remove(123);
        Iterator iterator = obj.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }

結果:
可見並沒有把相同的元素全部刪去,只刪除第一個相同的元素。
在這裏插入圖片描述

  • boolean removeAll(Collection coll 取當前集合的差集

例如:

@Test
    public void test3(){
        Collection obj = new ArrayList();
        Collection obj2 = Arrays.asList(123,"AA");
        obj.add(123);
        obj.add(123);
        obj.add("AA");
        obj.add("BB");
        obj.removeAll(obj2);
        Iterator iterator = obj.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }

結果:
在這裏插入圖片描述

  • boolean equals(Object obj) :集合是否相等
  • 這裏我們來看一個例子,我用一個Person類的一個對象,加到obj中,obj2用Arrays的方法把數組轉化爲List,其中元素也是Person類的一個對象。

person類如下所示:

package com.Collection;

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;
//
//        if (age != person.age) return false;
//        return name != null ? name.equals(person.name) : person.name == null;
//    }
//
//    @Override
//    public int hashCode() {
//        int result = name != null ? name.hashCode() : 0;
//        result = 31 * result + age;
//        return result;
//    }
}

測試單元如下:

	@Test
    public void test5(){
        Collection obj = new ArrayList();
        obj.add(new Person("LC",12));
        Collection obj2 = Arrays.asList(new Person("LC",12));
        boolean equals = obj.equals(obj2);
        System.out.println(equals);
    }

看看結果(Person類中的註釋沒打開):
在這裏插入圖片描述
現在我在Person類打開了註釋,再看看結果:

在這裏插入圖片描述
解釋:第一次判斷結果爲false,是因爲在執行equals方法的時候,調用的是Object裏面的equals方法
在這裏插入圖片描述
因爲地址值不同,所以返回false.
而第二種是自己重寫了equals方法,沒有按照地址值判斷,所以返回true

  • Object[] toArray() 轉成對象數組
    例子:
 @Test
    public void test6(){
        Collection obj = new ArrayList();
        obj.add(123);
        obj.add("AA");
        obj.add(new Person("LC",12));
        Object[] objects = obj.toArray();
        System.out.println(objects[1]);
    }

結果:
在這裏插入圖片描述

  • hashCode(): 獲取集合對象的哈希值
    例子:
	@Test
    public void test6(){
        Collection obj = new ArrayList();
        obj.add(123);
        obj.add("AA");
        obj.add(new Person("LC",12));
        System.out.println(obj.hashCode());
    }

結果:
在這裏插入圖片描述

  • iterator() 返回迭代器對象,用於集合遍歷

其實在試前面的方法的時候已經用到了。
例子:

	@Test
    public void test6(){
        Collection obj = new ArrayList();
        obj.add(123);
        obj.add("AA");
        obj.add(new Person("LC",12));
        Iterator iterator = obj.iterator();
        while(iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }

結果:
在這裏插入圖片描述
注意: Collection obj = new Collection(); //錯誤,因爲接口不能實例化
Collection接口雖然不能直接被使用, 但提供了集合以及集合元素的方法且Set接口和List接口都可以調用Collection接口的方法。

Collection的子接口(一)—List接口

鑑於Java中數組用來存儲數據的侷限性,我們通常使用List替代數組。
通過源代碼可以發現List接口繼承與Collecion接口
在這裏插入圖片描述
List特點:

  • List集合類中元素有序、且可重複,集合中的每個元素都有其對應的順序索引。
  • List容器中的元素都對應一個整數型的序號記載其在容器中的位置,可以根據序號存取容器中的元素。
  • JDK中List接口的實現類常用的有:ArrayList、LinkedList和Vector

List類的一些方法

List 除了從 Collection 集合繼承的方法外, List 集合裏添加了一些根據索引來操作集合元素的方法,下面就來了解一下它的一些方法.
這裏我用ArrayList來實現List接口中的一些方法

  • void add( int index, Object o) 在 index 位置插入o元素.
 @Test
    public void test(){
        ArrayList list  = new ArrayList();
        list.add("AA");
        list.add("BB");
        list.add("CC");
        list.add("DD");
        System.out.println(list);
        list.add(1,"RR");
        System.out.println(list);
    }

結果:
在這裏插入圖片描述

  • boolean addAll(int index, Collection eles) 從 index 位置開始將 eles 中的所有元素添加進來

例子:

@Test
    public void test(){
        ArrayList list  = new ArrayList();
        list.add("AA");
        list.add("BB");
        list.add("CC");
        list.add("DD");
        list.addAll(1, Arrays.asList("123","456"));
        System.out.println(list);
    }

結果:在這裏插入圖片描述

  • Object get( int index): 獲取指定 index 位置的元素

例子:

@Test
    public void test(){
        ArrayList list  = new ArrayList();
        list.add("AA");
        list.add("BB");
        list.add("CC");
        list.add("DD");
        Object o = list.get(1);
        System.out.println(o);
    }

結果:
在這裏插入圖片描述

  • int indexOf(Object obj):返回obj在集合中首次出現的位置,沒找到返回-1

例子:

@Test
    public void test(){
        ArrayList list  = new ArrayList();
        list.add("AA");
        list.add("BB");
        list.add("BB");
        list.add("BB");
        int num1 = list.indexOf("BB");
        int num2 = list.indexOf("Baa");
        System.out.println(num1+"    "+num2);
    }

結果:
在這裏插入圖片描述

  • int lastlndexOf(Object obj):返回obj在當前集合中末次出現的位置,沒找到返回-1

例子:

@Test
    public void test(){
        ArrayList list  = new ArrayList();
        list.add("AA");
        list.add("BB");
        list.add("BB");
        list.add("BB");
        int num1 = list.lastIndexOf("BB");
        int num2 = list.lastIndexOf("Baa");
        System.out.println(num1+"    "+num2);
    }

結果:
在這裏插入圖片描述

  • Object remove(int index):移除指定index位置的元素,並返回此元素
    例子:
@Test
    public void test(){
        ArrayList list  = new ArrayList();
        list.add("AA");
        list.add("BB");
        Object o = list.remove(1);
        System.out.println(o);
    }

結果:
在這裏插入圖片描述

  • Object set(int index,Object ele):設置指定index位置的元素爲ele,並返回之前在index位置的值

例子:

@Test
    public void test(){
        ArrayList list  = new ArrayList();
        list.add("AA");
        list.add("BB");
        Object o = list.set(1, "CC");
        System.out.println(o);
        System.out.println(list);
    }

結果:
在這裏插入圖片描述

  • List subList(int fromlndex,int tolndex):返回從fromlndex到tolndex位置的子集合

例子:

@Test
    public void test(){
        ArrayList list  = new ArrayList();
        list.add("AA");
        list.add("BB");
        list.add("CC");
        list.add("DD");
        List list1 = list.subList(1, 3);
        System.out.println(list1);
    }

結果:
在這裏插入圖片描述

List實現類之一----ArrayList

看ArrayList的源碼發現,ArrayList繼承於AbstractList, 實現了List、RandomAccess, Cloneable, java.io.Serializable。
在這裏插入圖片描述
ArrayList 是 List 接口的典型 實現類、主要實現類。本質上, ArrayList 是對象引用的 一個變長數組

ArrayList的構造方法

在這裏插入圖片描述

在這裏插入圖片描述
從構造方法中我們可以看見,默認情況下,elementData是一個大小爲0的空數組,當我們指定了初始大小的時候,elementData的初始大小就變成了我們所指定的初始大小了。

List實現類之二—LinkedList

LinkedList:雙向鏈表,內部沒有聲明數組,而是定義了Node類型的first和last,用於記錄首末元素。同時,定義內部類Node,作爲LinkedList中保存數據的基本結構。Node除了保存數據,還定義了兩個變量:
prev變量: 記錄前一個元素的位置
next變量: 記錄下一個元素的位置
在這裏插入圖片描述
對於 頻繁的插入或刪除元素 的操作,建議 使用 LinkedList 類,效率 較高

這是它的源碼:
在這裏插入圖片描述

LinkedList的一些方法

除了List中的一些方法,LinkedList還有一些方法。

  • void addFirst(Object obj)
  • void addLast(Object obj)
  • Object getFirst()
  • Object getLast()
  • Object removeFirst()
  • Object removeLast()
    就看一個例子,來了解下這些方法:
@Test
        public void test3(){
            LinkedList linkedList = new LinkedList();
            linkedList.add("AA");
            linkedList.add("BB");
            linkedList.add("CC");
            linkedList.add("DD");
            linkedList.add("EE");
            linkedList.add("FF");
            linkedList.addFirst("begin");
            linkedList.addLast("last");
            System.out.println(linkedList);
            System.out.println("***************");
            Object first = linkedList.getFirst();
            Object last = linkedList.getLast();
            System.out.println(first);
            System.out.println(last);
            Object o = linkedList.removeFirst();
            Object o1 = linkedList.removeLast();
            System.out.println(linkedList);
        }

結果:
在這裏插入圖片描述

Vector

Vector是一個古老的集合,JDK1.0就有了。大多數操作與ArrayList相同,區別之處在於Vector是線程安全的。
在各種list中,最好把ArrayList作爲缺省選擇。當插入、刪除頻繁時,使用LinkedList;Vector總是比ArrayList慢,所以儘量避免使用。

Vector的一些方法

  • void addElement (Object obj

  • void insertElementAt (Object obj,int index)

  • void setElementAt (Object obj,int index)

  • void removeElement (Object obj

  • void removeAllElements

看一個例子:

public  void test4(){
            Vector vector = new Vector();
            vector.addElement("aaa");
            vector.addElement("aaa");
            vector.addElement("bbb");
            vector.insertElementAt("ccc",1);
            System.out.println(vector);
            vector.setElementAt("ddd",1);
            System.out.println(vector);
            vector.removeElement("aaa");
            System.out.println(vector);
            vector.removeAllElements();
            System.out.println("現在還剩下元素"+vector);

        }

結果:
在這裏插入圖片描述

一道關於ArrayList/LinkedList/Vector的面試題

問題:請問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

Collection的子接口(二)—set接口

概述

  1. Set 接口 是 Collection 的子接口, set 接口沒有 提供額外 的方法

  2. Set 集合不允許包含相同的元素,如果試把兩個相同的元素加入同一個

  3. Set 集合中,則添加操作失敗。

  4. Set 判斷兩個對象是否相同不是使用 == 運算符,而是 根據 equals() 方法

Set實現類之一— Hashset

概述

  1. HashSet 是 Set 接口的典型實現,大多數時候使用 Set 集合時都使用這個實現類。
  2. HashSet 按 Hash 算法來存儲集合中的元素,因此具有很好 的 存取、查找、刪除性能。
  3. HashSet具有以下特點:
    不能保證元素的排列順序
    HashSet不是線程安全的
    集合元素可以是null
  4. HashSet 集合判斷兩個元素相等的標準:兩個對象通過hashCode()方法比較相等,並且兩個對象的equals()方法返回值也相等。
  5. 對於存放在Set容器中的對象,對應的類一定要重寫equals()和hashCode(Object obj)方法,以實現對象相等規則。即:“相等的對象必須具有相等的散列碼”。

Set的無序性和不可重複型
例子(這裏的Person類是我自己創建的):

@Test
    public void test(){
        HashSet set = new HashSet();
        set.add("AA");
        set.add("BB");
        set.add("CC");
        set.add("CC");
        set.add(new Person("LC",20));
        set.add(new Person("LC",20));
        System.out.println(set);
    }

猜猜結果是多少?
發現這裏把兩個Person類的對象都輸出來了
在這裏插入圖片描述
如果在重寫equals()和hashcode()方法,那會怎麼樣呢

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

        if (age != person.age) return false;
        return name != null ? name.equals(person.name) : person.name == null;
    }

    @Override
    public int hashCode() {
        int result = name != null ? name.hashCode() : 0;
        result = 31 * result + age;
        return result;
    }

此時輸出就只有一個Person對象了
在這裏插入圖片描述

向 HashSet 中添加元素的過程:

  1. 當向 HashSet 集合中存入一個元素時 ,HashSet 會調用該對象的 hashCode() 方法來得到該對象的 hashCode 值,然後根據 hashCode 值 ,通過某種散列函數決定該對象在 HashSet 底層數組中 的 存儲位置 。 這個散列函數會與底層數組的長度相計算得到在數組中的下標,並且這種散列函數計算還儘可能保證能均勻存儲元素,越是散列分佈該散列函數設計的越好(這就和數組結構有點關係了)

  2. 如果兩個元素的 hashCode() 值相等,會再繼續調用 equals 方法。如果 equals 方法結果爲 true 添加 失敗。如果 爲 false 那麼會保存該元素 但是該數組的位置已經有元素了那麼會通過鏈表的方式,繼續鏈接 。

  3. 如果 兩個元素的 equals() 方法返回 true ,但它們的 hashCode () 返回值不相等, hashSet 將會把它們存儲在不同的位置,但依然可以添加 成功。

Set實現類之二—LinkedHashset

概述

  1. LinkedHashSet 是HashSet的子類
  2. LinkedHashSet 根據元素的 hashCode值來決定元素的存儲位置,但它同時使用雙向鏈表維護元素的次序,這使得元素看起來是以插入順序保存的。
  3. LinkedHashSet插入性能略低於HashSet,但在迭代訪問Set裏的全部元素時有很好的性能。
  4. LinkedHashSet不允許集合元素重複。

看一個關於LinkedHashset的例子

@Test
    public void test(){
        LinkedHashSet set = new LinkedHashSet();
        set.add("AA");
        set.add("BB");
        set.add("CC");
        set.add(new Person("LC",20));
        set.add("a");
        set.add("b");
        System.out.println(set);
    }

輸出結果:
可以發現它的輸出結果順序就是添加的順序。
在這裏插入圖片描述
在Linkedhashset的底層結構
在這裏插入圖片描述

Set實現類之三—Treeset

概要:

  • TreeSet 是 SortedSet 接口的實現類, TreeSet 可以確保集合元素處於排序 狀態。

  • TreeSet 底層使用 紅黑樹 結構存儲數據

  • TreeSet 兩種排序方法: 自然排序 和 定製排序 。默認情況下, TreeSet 採用自然排序。
    自然排序:TreeSet 會調用集合元素的compare To(Object obj)方法來比較元素之間的大小關係,然後將集合元素按升序(默認情況)排列
    定製排序:通過 Comparator 接口來實現。 需要重寫 compare(T o1,T o2) 方法

例子:

 @Test
    public void test2(){
        TreeSet treeSet = new TreeSet();
        treeSet.add(1);
        treeSet.add(3);
        treeSet.add(5);
        treeSet.add(2);
        treeSet.add(4);
        treeSet.add(6);
        Object first = treeSet.first();
        Object last = treeSet.last();
        Object o = treeSet.higher(5);
        System.out.println(treeSet);
        System.out.println(first);
        System.out.println(last);
        System.out.println(o);
    }

結果:
在這裏插入圖片描述

如果有錯誤,請指出 😄

喜歡的話,就點個贊吧!!!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章