java類集框架之Collection及其子接口List、Set詳解

1. 類集概述

java類集框架位於java.util包下,是JDK1.2產生的,它的本質其實就是動態數組。
動態數組:當元素個數達到最大值時,動態增加容量,解決數組定長的問題
在java的類集中,提供了兩個最爲核心的接口:Collection、Map
Collection接口及其子接口:每次進行數據操作時,都是對單個對象進行處理
Map接口:對鍵值對進行操作處理

2. 關於Collection接口
2.1 Collection的定義和常用方法

Collection接口是單個對象保存的最頂層的父接口它的構造方法如下:
public interface Collection extends Iterable
看一下他有哪些常用方法:
在這裏插入圖片描述
其中我們最常使用有兩個方法:
add() :向集合中添加元素
iterator():取得集合的迭代器
由於Collection接口制定了數據的存儲標準,而沒有區分具體的存儲類型,因此我們在使用時一般不直接使用Collection接口,而是使用它的兩個子接口
List:允許元素重複
Set:不允許元素重複

2.2 List接口

List接口除了有Collection接口提供的那些方法之外。還有兩個自己獨有的方法
get(int index):根據指定索引獲取元素
set(int index, E element): 修改指定索引處的元素,返回修改前的元素
在List接口下有三個重要子類:ArrayList、LinkedList、Vector
ArrayList:
public class ArrayList extends AbstractList implements List

LinkedList:
public class LinkedList extends AbstractSequentialList implements List
public abstract class AbstractSequentialList extends AbstractList

Vector:
public class Vector extends AbstractList implements List

AbstractList:
public abstract class AbstractList extends AbstractCollection implements List
我們可以看到ArstractList已經實現了List,但是ArrayList它們還要自己實現List接口。這是因爲對於數組來說有一些基本的增刪改查操作,我們把這些方法就放在ArstractList中,但是ArrayList等又有一些自己特有的方法,這時候就需要實現List接口去擴展自己的方法。
在這裏插入圖片描述
下面我們來具體看看List下的子類
2.2.1 ArrayList
ArrayList底層是一個對象數組,聲明一個ArrayList對象時長度爲0,只有第一次使用時,長度纔會被置爲10。這是一種懶加載策略。對集合的增刪改查都是異步處理,性能較高,線程不安全。
2.2.2 Vector
底層實現是一個對象數組,聲明一個Vector,初始化長度是10
對集合的修改都採用同步處理(直接在方法上使用內建鎖),性能較低,線程安全
當數組長度不夠用時,擴容策略變爲原來數組的2倍
2.2.3 LinkedList
基於鏈表實現的動態數組

我們都直到List接口允許存儲重複元素,如果我們想用List來存儲自定義對象時,這時我們就需要自己覆寫equals()方法了。因爲當我們在使用List中的contains()和remove()方法時,它們都需要用到equals方法,對於基本類型和引用類型而言,Object已經幫他們覆寫了equals()。但是自定義類並沒有覆寫,因此我們需要自己覆寫。
下面通過一個例子,來看看如何使用List來存儲自定義類對象。

class Person{
    private String name;
    private int 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 boolean equals(Object obj) {
        if(obj == this){
            return true;
        }if(obj == null){
            return false;
        }if(!(obj instanceof Person)){
            return false;
        }
        Person per = (Person)obj;
        return this.age == per.age && this.name.equals(per.name);
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}
public class Test {
   public static void main(String[] args) {
        Person per1 = new Person("張三",18); 1
        Person per2 = new Person("李四",20);  2
        Person per3 = new Person("王五",22);   3
        List<Person> list = new ArrayList<>(); 
        list.add(per1);
        list.add(per2);
        list.add(per3);
      System.out.println(list.contains(new Person("張三",18)));
      list.remove(new Person("王五",22));
       System.out.println(list);
       // System.out.println(list.contains(per1));
   }
}
3. Set接口

Set接口沒有擴充方法,Set接口中的方法與Collection完全一致,常用兩個子類HashSet、TreeSet
3.1 HashSet ( 無序存儲) – HashMap – 底層使用哈希表+紅黑樹
不允許元素重複,並且無序存儲(根據hash碼來存放元素)
允許存放null,有且僅有一個null

重複元素的判斷
TreeSet與TreeMap依靠Comparator或Comparable接口來區分重複元素
自定義類要想保存在TreeSet或TreeMap中:
Ⅰ. 要麼該類直接實現Comparable接口,覆寫compare to方法
Ⅱ. 要麼實現一個比較器傳入TreeSet或TreeMap來進行外部比較

而HashSet與HashMap並不依賴比較接口。此時要想區分自定義元素是否重複,需要同時覆寫Object中的hashCode以及equals( )。

3.2 TreeSet (有序存儲)–TreeMap – 底層基於紅黑樹
不允許元素重複(用Compareable或者Compartor判斷是否重複),並且按照升序排序,不允許存放Null(會空指針異常)
要想使用自定義類作爲TreeSet存儲(想利用Treeset排序),該類必須覆寫Compareable接口,或者向TreeSet傳入比較器(即Compartor接口)。看看比較器是什麼:

java.lang.Comparable接口(內部比較器):
若一個類實現了Comparable接口,就意味着該類支持排序
public int compareTo(Object o),類中所有屬性都要參與運算。
a. >0 表示當前對象大於比較對象
b. =0 表示當前對象等於比較對象
c. <0 表示當前對象小於比較對象

Comparator(外部排序接口)
若要控制某個自定義類的順序,而該類本身不支持排序(該類本身沒有實現Comparable),我們可以建立一個該類的“比較器”來進行排序
“比較器”:實現了Comparator接口的類作爲比較器,通過該類比較器來進行類的排序
public int compare(T o1,T o2):
返回正數表示 o1 > o2
返回0表示 o1 = o2
返回小數表示 o1 < o2
實現了Comparator接口進行第三方排序(是一種策略模式)此方法更加靈活,可以輕鬆改變策略進行第三方的排序算法。
看一個傳入外部比較器的例子:

import java.util.Comparator;
import java.util.Set;
import java.util.TreeSet;
class Person{
    private String name;
    private int 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;
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
class AscComparator implements Comparator<Person>{
    @Override
    public int compare(Person o1, Person o2) {
        return o1.getAge()-o2.getAge();
    }
}
public class Test {
    public static void main(String[] args) {
        Set<Person> set = new TreeSet<>(new AscComparator());
        set.add(new Person("張三",18));
        set.add(new Person("李四",25));
        System.out.println(set);
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章