簡單的聊一下JAVA集合(SXL),有什麼不對的歡迎指正!

1、ArrayList

數組集合應用java

// ArraysList 增刪慢 查詢快
        // 根據源碼 無參構造方法建立出來的是長度爲0的數組{}
        List<Integer> list = new ArrayList<>();
        // 此時add方法進行源碼擴容
        list.add(100);
        System.out.println(list.get(0));

add()方法擴容源碼

public boolean add(E e) {
        // 不須要關注
        modCount++;
        // e對象 elementData集合數組元素 size當前數組長度
        add(e, elementData, size);
        // 無論成功失敗 均返回true
        return true;
    }
    
    private void add(E e, Object[] elementData, int s) {
        // 知足條件 進入擴容算法 否則就進行正常賦值操做
        if (s == elementData.length)
            elementData = grow();
        elementData[s] = e;
        size = s + 1;
    }
    
    private Object[] grow() {
        // 至少須要加一個長度 
        return grow(size + 1);
    }
    
    private Object[] grow(int minCapacity) {
        return elementData = Arrays.copyOf(elementData,
                                           newCapacity(minCapacity));
    }

    private int newCapacity(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        // 新長度加上舊長度的0.5倍
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity <= 0) {
            if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
                // DEFAULT_CAPACITY 默認長度10
                return Math.max(DEFAULT_CAPACITY, minCapacity);
            // 超出最大二進制,符號會改變,會變爲負數
            if (minCapacity < 0) // overflow
                throw new OutOfMemoryError();
            return minCapacity;
        }
        
        // MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8
        return (newCapacity - MAX_ARRAY_SIZE <= 0)
            ? newCapacity
            : hugeCapacity(minCapacity);
    }

    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE)
            ? Integer.MAX_VALUE
            : MAX_ARRAY_SIZE;
    }

2、LinkedList

// LinkedList: 使用雙向鏈表結構,增刪快,查找慢
        // (這種結構和ArrayList的數組結構正好是互補狀態)
        LinkedList<Integer> ll = new LinkedList<>();

        // 模擬棧結構
        // 壓棧
        ll.push(100);
        ll.push(200);
        // 彈棧
        Integer i = ll.pop();
        // 200
        System.out.println(i);
        // 1
        System.out.println(ll.size());

        // 下面註釋參考 不建議使用
        // 添加集合中第一個元素
        // ll.addFirst(100);
        // ll.addFirst(200);
        // 移除集合中第一個元素
        // Integer removeData = ll.removeFirst();
        // 200
        // System.out.println(removeData);
        // 1
        // System.out.println(ll.size());

3、Vector

用法和ArrayList基本一致,是線程安全的。面試

// 10 初始化長度 20 擴容增量 此處是相較於ArrayList不一樣之處
        List<Integer> v = new Vector<>(10, 20);
        v.add(100);
        v.add(200);

4、Iterator和ListIterator

// Iterator 迭代器 做用遍歷集合
        // Iterator迭代Collection下List和Set ListIterator迭代List下面的集合
        List<Integer> list = new ArrayList<>();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        list.add(5);

        Iterator<Integer> iterator = list.iterator();

        iterator.next();
        // 必需要有值才能移除即前面調用next()方法,固然沒值也會報錯
        iterator.remove();;
        // 4
        System.out.println(list.size());

        // 判斷迭代器下個是否有值
        while(iterator.hasNext()) {
            // 迭代器往下走,並取值
            Integer i = iterator.next();
            // 輸出 2 3 4 5
            System.out.println(i);
        }

        // 用法和iterator差很少
        ListIterator<Integer> listIterator = list.listIterator();
        // 獲取向上走的值
        listIterator.hasPrevious();
        // 添加
        listIterator.add(10);
        // 設置
        listIterator.next();
        listIterator.set(200);
        listIterator.previous();
        // 5
        System.out.println(list.size());
        while(listIterator.hasNext()) {
            // 輸出 200 3 4 5
            System.out.println(listIterator.next());
        }

5、Set

Set集合是沒有重複的元素,包括null只會存在一個算法

5.1 HashSet

// HashSet是散列存放的數據結構(哈希表)
        // 本質是 map = new HashMap<>()
        // 因爲已經存在雙值存儲的哈希表 因此這邊重複利用了造成如今的單值存儲的哈希表
        Set<String> set = new HashSet<>();
        // map.put(e, PRESENT)
        set.add("人有悲歡離合");
        set.add("月有陰晴圓缺");
        set.add("希望人長久");
        set.add("希望人長久");
        set.add("千里共嬋娟");
        set.add("千里共嬋娟");
        Iterator<String> iterator = set.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }

5.2 TreeSet

public static void main(String[] args) {
        // TreeSet 使用二叉樹進行存儲的 有序(天然順序)
        Set<Person> set = new TreeSet<>();
        Person p1 = new Person("張三", 13);
        Person p2 = new Person("李四", 14);
        Person p3 = new Person("麻五", 14);
        set.add(p1);
        set.add(p2);
        set.add(p3);
        // 遍歷前需制定本身的排序規則, 不然可能報錯
        // Person{name='張三', age=13}
        // Person{name='李四', age=14}
        // 比較規則相同的值,不被儲存
        for (Person p : set) {
            System.out.println(p);
        }


        // set.add("C");
        // set.add("B");
        // set.add("A");
        // set.add("D");
        // A B C D
        // Iterator<String> iterator = set.iterator();
        // while(iterator.hasNext()) {
        //    System.out.println(iterator.next());
        // }
    }

    static class Person implements Comparable<Person> {

        private String name;

        private int age;

        @Override
        public int compareTo(Person o) {
            // this與0比較
            // 返回this小/0/大
            if (this.age > o.age) {
                return 1;
            } else if (this.age == o.age) {
                return 0;
            }
            return -1;
        }

        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 +
                    '}';
        }
    }

6、Map

Map(Mapping 映射)集合存儲的是 鍵值對 數據,Map的鍵不可重複。
影響HashMap的實例化性能的是初始容量和負載因子。
HashMap/Hashtable/ConcurrentHashMap TreeMap/LinkedHashMap使用方法基本一致。數組

HashMap是線程不安全,效率高。HashTable線程安全, 效率低。
ConcurrentHashMap採用分段鎖機制,保證線程安全,效率較高。安全

TreeMap是有序的排。
LinkedHashMap存儲有序。數據結構

6.1 HashMap

Map<String, String> map = new HashMap<>();
        // 存值
        map.put("k1", "v1");
        // 取值 v1
        System.out.println(map.get("k1"));
        map.put("k2", "v2");

        // 遍歷
        Set<String> set = map.keySet();
        for (String key : set) {
            // k1->v1
            // k2->v2
            System.out.println(key + "->" + map.get(key));
        }

        // 轉爲Collection集合
        Collection<String> c = map.values();
        for (String s : c) {
            System.out.println(s);
        }

HashMap源碼粗解析

// 構造方法
    public HashMap() {
        // 默認加載因子0.75f
        this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
    }

    public V put(K key, V value) {
        // 先計算鍵的hash值,而後調用putVal
        return putVal(hash(key), key, value, false, true);
    }

    final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
        // n是桶(數組)的長度
        Node<K,V>[] tab; Node<K,V> p; int n, i;
        // table是默認的16個長度的數組賦值給tab
        if ((tab = table) == null || (n = tab.length) == 0)
            // resize擴容算法 n擴容以後的長度
            n = (tab = resize()).length;
        // (n - 1) & hash 是取餘後的長度   數組下標沒有值直接賦值
        if ((p = tab[i = (n - 1) & hash]) == null)
            tab[i] = newNode(hash, key, value, null);
        else {
            Node<K,V> e; K k;
            // key存在新值覆蓋老值
            if (p.hash == hash &&
                ((k = p.key) == key || (key != null && key.equals(k))))
                e = p;
            // 判斷是樹節點 按紅黑樹套路進行存儲 
            else if (p instanceof TreeNode)
                e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
            // 鏈表套路進行賦值
            else {
                for (int binCount = 0; ; ++binCount) {
                    // 非重複值操做
                    if ((e = p.next) == null) {
                        p.next = newNode(hash, key, value, null);
                        // 這邊是二叉樹操做
                        if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                            treeifyBin(tab, hash);
                        break;
                    }
                    // 重複值操做
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        break;
                    p = e;
                }
            }
            // 前面e被賦值,進入此方法
            if (e != null) { // existing mapping for key
                V oldValue = e.value;
                if (!onlyIfAbsent || oldValue == null)
                    e.value = value;
                afterNodeAccess(e);
                return oldValue;
            }
        }
        // 增長修改次數
        ++modCount;
        // 判斷是否到了臨界值
        if (++size > threshold)
            // 擴容
            resize();
        afterNodeInsertion(evict);
        return null;
    }

總結

在文章的最後做者爲你們整理了不少資料!包括java核心知識點+全套架構師學習資料和視頻+一線大廠面試寶典+面試簡歷模板+阿里美團網易騰訊小米愛奇藝快手嗶哩嗶哩面試題+Spring源碼合集+Java架構實戰電子書等等!
歡迎關注公衆號:前程有光,領取!架構

相關文章
相關標籤/搜索