集合心得總結

  • 2021 年 12 月 31 日
  • 筆記

為什麼需要集合? 數組有不足:擴容麻煩 保存元素類型固定,同一數組無法改變 ——> 引出集合的概念

集合體系

集合分為兩大類 一類是Collection(一組對象) 一類是Map(一組鍵值對)

底層維護實現關係

ArrayList/Vector實現Collection的List介面 底層是可變類型數組Object[]

LinkedList實現Collection的List介面 底層是雙向鏈表

TreeSet實現了Collection的Set介面 底層是TreeMap

HashSet實現了Collection的Set介面 底層是HashMap

LinkedHashSet實現了Map介面 底層是LinkedHashMap

Hashtable實現了Map介面 底層Entry數組

HashMap實現了Map介面 底層是Node類型數組table 在JDK7中 實現形式是數組+鏈表 在JDK8以後 實現形式是數組+鏈表+紅黑樹

LinkedHashMap實現了Map介面 底層是數組+雙向鏈表

選擇

1.判斷存儲的類型

一組對象/一組鍵值對

2.一組對象【單列】

Collection介面

允許重複:List

 增刪多:LinkedList【雙向鏈表】

 改查多:ArrayList/Vector【可變類型Object數組】

不允許重複:Set 底層都是Map介面的實現類 而Map的Key不允許重複

 無序:HashSet

 排序:TreeSet

 插入和取出順序一致: LinkedHashSet

3.一組鍵值對

Map介面 Key不允許重複 可以為空 Values可以重複 可以為null(多個) 一對K-V —> 放在HashMap$Node Node實現了Entry介面 可以說一對K-V是一個Entry

    1. k-v 最後是HashMap$Node
    2. k-v為了方便程式設計師的遍歷 還會創建 EntrySet 集合 該集合存放的元素的類型 Entry
       而一個Entry對象 就有k,v EntrySet<Entry<k,v>> 即 transicent Set<Map.Entry<k,v>> entrySet;
    3. entrySet 中 定義的類型是 Map.Entry 但是實際上存放的還是 HashMap$Node
       這是因為 static class Node<K,V> implements Map.Entry<K,V>
    4. 當把HashMap$Node 對象 存放到 entrySet 就方便我們的遍歷
      K getKey(); V getValue();

鍵無序:HashMap

鍵排序:TreeMap

鍵插入和取出一致:LinkedHashMap

讀取文件:Properties

剖析類

Vector 安全 效率低---ArrayList 不安全 效率高  !!!擴容機制

ArrayList擴容完整過程

TreeSet–TreeMap 強調訂製排序(匿名內部類)

image
image

HashSet–HashMap執行緒不安全 !!!擴容機制

image
image
image
image
重寫hashCode equals 來控制當什麼條件相同時返回相同的hashCode 就不能添加元素

LinkedHashSet

加入順序和取出元素/數據的順序一致
LinkedHashSet 底層維護的是一個LinkedHashMap(是HashMap的子類)
LinkedHashSet 底層結構 (數組 + 雙向鏈表)
添加第一次時 直接將 數組table 擴容到16 存放的結點類型 LinkedHashMap\(Entry
數組是 HashMap\)
Node[] 存放的元素/數據是 dHashMap$EntrLinkey類型

	繼承關係是在內部類完成
        static class Entry<K,V> extends HashMap.Node<K,V> {
    Entry<K,V> before, after;
    Entry(int hash, K key, V value, Node<K,V> next) {
        super(hash, key, value, next);
    }
}

HashTable

Hashtable底層
底層有一個數組 Hashtable$Entry[] 初始化大小為11 臨界值 threshold 8 = 11 * 0.75 擴容 按照自己的擴容機制來進行即可 執行 方法 addEntry(hash, key, value, index); 添加 k-v 裝到Entry 當 if (count >= threshold) 滿足時 進行擴容 按照 int newCapacity = (oldCapacity << 1) + 1;

方法

Collection:

Collections工具類方法
image
image
image
image

List/Set方法

add

remove

contains

size

isEmpty

addAll

containsAll

removeAll

get List介面有 Set介面無

Map:

put

remove

get

size

isEmpty

clear

containsKey

遍歷

Collection:

Iterator
image
增強for
image
普通for
image
Set介面實現類沒有get方法 不能通過普通for遍歷

Map

image
image
image

Collections類

image
image

集合關係密切—–> 泛型配合使用

傳統方法 不能對加入集合的元素進行約束 可能存在安全隱患  
遍歷的時候 需要類型轉換 當數據量比較大的時候  會影響效率
![image](//img2020.cnblogs.com/blog/2679279/202112/2679279-20211228152459833-2069123739.png)

經典題目
image

點擊查看程式碼
public class Main {
    public static void main(String[] args) {

        ArrayList<Employee> employees = new ArrayList<>();
        Employee em1 = new Employee("zhc", 20000, new MyDate(2002, 7, 9));
        Employee em2 = new Employee("myh", 10000, new MyDate(2000, 4, 2));
        Employee em3 = new Employee("zhc", 5000, new MyDate(2001, 2, 5));
        employees.add(em2);
        employees.add(em1);
        employees.add(em3);

        System.out.println("排序前");
        System.out.println(employees);

        employees.sort(new Comparator<Employee>() {
            @Override
            public int compare(Employee emp1, Employee emp2) {
                //先按照 name 排序,如果 name 相同,則按生日日期的先後排序。【即:訂製排序】
                //先對傳入的參數進行驗證
                if(!(emp1 instanceof Employee && emp2 instanceof Employee)) {
                    System.out.println("類型不正確..");
                    return 0;
                }
                //比較 name
                int i = emp1.getName().compareTo(emp2.getName());
                if(i != 0) {
                    return i;
                }

                return emp1.getBirthday().compareTo(emp2.getBirthday());//動態綁定到MyDate類的compareto方法
            }
        });

        System.out.println("排序後");
        System.out.println(employees);




        }
    }


@SuppressWarnings({"all"})
class Employee {
    private String name;
    private double sal;
    private MyDate birthday;

    public Employee(String name, double sal, MyDate birthday) {
        this.name = name;
        this.sal = sal;
        this.birthday = birthday;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getSal() {
        return sal;
    }

    public void setSal(double sal) {
        this.sal = sal;
    }

    public MyDate getBirthday() {
        return birthday;
    }

    public void setBirthday(MyDate birthday) {
        this.birthday = birthday;
    }

    @Override
    public String toString() {
        return "\nEmployee{" +
                "name='" + name + '\'' +
                ", sal=" + sal +
                ", birthday=" + birthday +
                '}';
    }
}
	
	public class MyDate implements Comparable<MyDate> {

        private int year;
        private int month;
        private int day;

        public MyDate(int year, int month, int day) {
            this.year = year;
            this.month = month;
            this.day = day;
        }

        public int getMonth() {
            return month;
        }

        public void setMonth(int month) {
            this.month = month;
        }

        public int getDay() {
            return day;
        }

        public void setDay(int day) {
            this.day = day;
        }

        public int getYear() {
            return year;
        }

        public void setYear(int year) {
            this.year = year;
        }

        @Override
        public String toString() {
            return "MyDate{" +
                    "month=" + month +
                    ", day=" + day +
                    ", year=" + year +
                    '}';
        }

        @Override
        public int compareTo(MyDate o) { //把對 year - month - day
            //如果year相同 就比較Month
            int yearMinus = year - o.getYear();
            if (yearMinus != 0) {
                return yearMinus;
            }
            //如果year相同 就比較month
            int monthMinus = month - o.getMonth();
            if (monthMinus != 0) {
                return monthMinus;
            }
            return day - o.getDay();
        }
    }



自定義泛型

自定義泛型類

·基本語法
class 類名 <T,R> {
成員
}
·細節
普通成員可以使用泛型 屬性 方法
使用泛型的數組 不能初始化
靜態方法中不能使用類的泛型
泛型類的類型 是在創建對象時確定的 因為創建對象時 需要指定類型
如果在創建對象時 沒有指定類型 默認為Object

自定義泛型介面

·基本語法
interface 介面名 <T,R> {

}

·細節
介面中 成員是靜態性質的 所以不能使用泛型
泛型介面的類型 在繼承介面 或者 實現介面 是確定
沒有指定類型 默認為Object

自定義泛型方法

·細節
泛型方法 可以定義在普通類 也可以定義在泛型類中
當泛型方法被調用時 類型會確定
public void eat(E e) 修飾符後沒有 <T,R> eat 方法不是 泛型方法 而是使用了泛型
image