Java集合类及内部部分实现浅析

本文深入探讨Java集合框架的内部实现,包括List、Set、Map的主要类型及其特性。详细解析了ArrayList、LinkedList、HashSet、TreeSet、HashMap等核心类的运作原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Java集合类的简单结构图:



事实上Collection的父接口为 Iterable

目的:简单的了解一下Java常用集合的特性以及内部实现。
参考博客: http://blog.sina.com.cn/s/blog_3fba24680100y2yr.html
常用List集合:
特性:
有顺序的,元素可以重复;
遍历:for,迭代;
排序:Comparable Comparator Collections.sort()
ArrayList:
用数组实现的List;
特点:查询效率高,增删效率低 轻量级 线程不安全;
部分源码分析:
构造:
Java代码
  1. private transient Object[] elementData;
  2. public ArrayList(int initialCapacity) {
  3. super();
  4. if (initialCapacity < 0)
  5. throw new IllegalArgumentException("Illegal Capacity: "+
  6. initialCapacity);
  7. this.elementData = new Object[initialCapacity];
  8. }
  9. public ArrayList() {
  10. this(10);
  11. }
    private transient Object[] elementData;
    
    public ArrayList(int initialCapacity) {
        super();
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        this.elementData = new Object[initialCapacity];
    }

    public ArrayList() {
        this(10);
    }
    

这段源代码表示的是一个ArrayList的内部实现为一个Object数组,重载的两个构造方法,默认长度为10。
增加元素:
Java代码
  1. public boolean add(E e) {
  2. ensureCapacityInternal(size + 1); // Increments modCount!!
  3. elementData[size++] = e;
  4. return true;
  5. }
  6. public boolean addAll(Collection<? extends E> c) {
  7. Object[] a = c.toArray();
  8. int numNew = a.length;
  9. ensureCapacityInternal(size + numNew); // Increments modCount
  10. System.arraycopy(a, 0, elementData, size, numNew);
  11. size += numNew;
  12. return numNew != 0;
  13. }
     public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }

    public boolean addAll(Collection<? extends E> c) {
        Object[] a = c.toArray();
        int numNew = a.length;
        ensureCapacityInternal(size + numNew);  // Increments modCount
        System.arraycopy(a, 0, elementData, size, numNew);
        size += numNew;
        return numNew != 0;
    }
    

添加对象的代码块,size表示数组长度。后一个为添加集合对象的代码块。

删除元素:
Java代码
  1. public E remove(int index) {
  2. rangeCheck(index);
  3. modCount++;
  4. E oldValue = elementData(index);
  5. int numMoved = size - index - 1;
  6. if (numMoved > 0)
  7. System.arraycopy(elementData, index+1, elementData, index,
  8. numMoved);
  9. elementData[--size] = null; // Let gc do its work
  10. return oldValue;
  11. }
     public E remove(int index) {
        rangeCheck(index);

        modCount++;
        E oldValue = elementData(index);

        int numMoved = size - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        elementData[--size] = null; // Let gc do its work

        return oldValue;
    }
    

首先检查下标是否越界,List删除后会自懂向前移动下标向前移动一位又是通过 System.arraycopy(elementData, index+1, elementData, index,numMoved);来实现。

那么ArrayList是怎么实现容量自增的呢?
ensureCapacityInternal(size+numNew)表示数组容量的自增函数,调用下面的函数:
Java代码
  1. private void grow(int minCapacity) {
  2. // overflow-conscious code
  3. int oldCapacity = elementData.length;
  4. int newCapacity = oldCapacity + (oldCapacity >> 1);
  5. if (newCapacity - minCapacity < 0)
  6. newCapacity = minCapacity;
  7. if (newCapacity - MAX_ARRAY_SIZE > 0)
  8. newCapacity = hugeCapacity(minCapacity);
  9. // minCapacity is usually close to size, so this is a win:
  10. elementData = Arrays.copyOf(elementData, newCapacity);
  11. }
     private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);
    }
    


LinkedList:
底层用双向循环链表实现的List;
特点:查询效率低,增删效率高;
构造:
Java代码
  1. transient Node<E> first;
  2. transient Node<E> last;
  3. public LinkedList() {
  4. }
  5. public LinkedList(Collection<? extends E> c) {
  6. this();
  7. addAll(c);
  8. }
    transient Node<E> first;
    transient Node<E> last;
    public LinkedList() {
    }
    public LinkedList(Collection<? extends E> c) {
        this();
        addAll(c);
    }
    

对于定义来说没有数组,却有个Node对象来看看静态内部类Node的结构:
Java代码
  1. private static class Node<E> {
  2. E item;
  3. Node<E> next;
  4. Node<E> prev;
  5. Node(Node<E> prev, E element, Node<E> next) {
  6. this.item = element;
  7. this.next = next;
  8. this.prev = prev;
  9. }
  10. }
    private static class Node<E> {
        E item;
        Node<E> next;
        Node<E> prev;

        Node(Node<E> prev, E element, Node<E> next) {
            this.item = element;
            this.next = next;
            this.prev = prev;
        }
    }
    

双向链表结构更像是一群牵着手的孩子只知道前后是谁。

添加元素:
Java代码
  1. void linkLast(E e) {
  2. final Node<E> l = last;
  3. final Node<E> newNode = new Node<>(l, e, null);
  4. last = newNode;
  5. if (l == null)
  6. first = newNode;
  7. else
  8. l.next = newNode;
  9. size++;
  10. modCount++;
  11. }
    void linkLast(E e) {
        final Node<E> l = last;
        final Node<E> newNode = new Node<>(l, e, null);
        last = newNode;
        if (l == null)
            first = newNode;
        else
            l.next = newNode;
        size++;
        modCount++;
    }
    

就是一个Node持有另个一Node的引用,形成以个链条。
删除元素:
Java代码
  1. E unlink(Node<E> x) {
  2. // assert x != null;
  3. final E element = x.item;
  4. final Node<E> next = x.next;
  5. final Node<E> prev = x.prev;
  6. if (prev == null) {
  7. first = next;
  8. } else {
  9. prev.next = next;
  10. x.prev = null;
  11. }
  12. if (next == null) {
  13. last = prev;
  14. } else {
  15. next.prev = prev;
  16. x.next = null;
  17. }
  18. x.item = null;
  19. size--;
  20. modCount++;
  21. return element;
     E unlink(Node<E> x) {
        // assert x != null;
        final E element = x.item;
        final Node<E> next = x.next;
        final Node<E> prev = x.prev;

        if (prev == null) {
            first = next;
        } else {
            prev.next = next;
            x.prev = null;
        }

        if (next == null) {
            last = prev;
        } else {
            next.prev = prev;
            x.next = null;
        }

        x.item = null;
        size--;
        modCount++;
        return element;
    }
    

先找到元素再赋值为null,并接上前面的。
Vector:
底层用数组实现List接口的另一个类;
特点:重量级,占据更多的系统开销,线程安全;
Vector与ArrayList基本上一致,最大的差别于在一些方法上使用了synchronized关键字,使其变成线程安全。

----------------------------------------------------------------------------------

Set:
无顺序的,元素不可重复(值不相同);
遍历:迭代;
排序:SortedSet
HashSet:
采用哈希算法来实现Set接口;
唯一性保证:重复对象equals方法返回为true;
重复对象hashCode方法返回相同的整数,不同对象hashCode尽量保证不同(提高效率);
构造:
Java代码
  1. private transient HashMap<E,Object> map;
  2. private static final Object PRESENT = new Object();
  3. public HashSet() {
  4. map = new HashMap<>();
  5. }
    private transient HashMap<E,Object> map;
    private static final Object PRESENT = new Object();
     public HashSet() {
        map = new HashMap<>();
    }
    

实际上的HashSet内部的实现为一个HashMap(下面看看HashMap的组成)。
添加元素:
Java代码
  1. public boolean add(E e) {
  2. return map.put(e, PRESENT)==null;
  3. }
    public boolean add(E e) {
        return map.put(e, PRESENT)==null;
    }
    

由源代码块可以看出HashSet添加一个元素时,添加的值为HashMap的Key值,而一个Object对象却为一个Value值。

删除元素:
Java代码
  1. public boolean remove(Object o) {
  2. return map.remove(o)==PRESENT;
  3. }
    public boolean remove(Object o) {
        return map.remove(o)==PRESENT;
    }
    

那么HashSet无序不重复的属性则来自于HashMap。
TreeSet:
在元素添加的同时,进行排序。也要给出排序规则;
唯一性保证:根据排序规则,compareTo方法返回为0,就可以认定两个对象中有一个是重复对象。
结构:
Java代码
  1. private transient NavigableMap<E,Object> m;
  2. private static final Object PRESENT = new Object();
    private transient NavigableMap<E,Object> m;
    private static final Object PRESENT = new Object();
    

----------------------------------------------------------------------------------

Map:
元素是键值对:key唯一不可重复,value可重复;
遍历:先迭代遍历key的集合,再根据key得到value;
SortedMap:元素自动对key排序
HashMap:
轻量级,线程不安全,允许key或者value是null;
构造:
Java代码
  1. transient Entry[] table;
  2. public HashMap(int initialCapacity, float loadFactor) {
  3. if (initialCapacity < 0)
  4. throw new IllegalArgumentException("Illegal initial capacity: " +
  5. initialCapacity);
  6. if (initialCapacity > MAXIMUM_CAPACITY)
  7. initialCapacity = MAXIMUM_CAPACITY;
  8. if (loadFactor <= 0 || Float.isNaN(loadFactor))
  9. throw new IllegalArgumentException("Illegal load factor: " +
  10. loadFactor);
  11. // Find a power of 2 >= initialCapacity
  12. int capacity = 1;
  13. while (capacity < initialCapacity)
  14. capacity <<= 1;
  15. this.loadFactor = loadFactor;
  16. threshold = (int)(capacity * loadFactor);
  17. [color=red]table = new Entry[capacity];[/color]
  18. init();
  19. }
    transient Entry[] table;
       public HashMap(int initialCapacity, float loadFactor) {
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal initial capacity: " +
                                               initialCapacity);
        if (initialCapacity > MAXIMUM_CAPACITY)
            initialCapacity = MAXIMUM_CAPACITY;
        if (loadFactor <= 0 || Float.isNaN(loadFactor))
            throw new IllegalArgumentException("Illegal load factor: " +
                                               loadFactor);

        // Find a power of 2 >= initialCapacity
        int capacity = 1;
        while (capacity < initialCapacity)
            capacity <<= 1;

        this.loadFactor = loadFactor;
        threshold = (int)(capacity * loadFactor);
        [color=red]table = new Entry[capacity];[/color]
        init();
    }
    

从构造方法分可以看出其为一个Entry数组
Entry主要属性:
Java代码
  1. final K key;
  2. V value;
  3. Entry<K,V> next;
     final K key;
        V value;
        Entry<K,V> next;
    

该源码片段可以看出Entry以及key值一旦赋值就无法更改。
添加元素:
Java代码
  1. public V put(K key, V value) {
  2. if (key == null)
  3. return putForNullKey(value);
  4. int hash = hash(key.hashCode());
  5. int i = indexFor(hash, table.length);
  6. for (Entry<K,V> e = table[i]; e != null; e = e.next) {
  7. Object k;
  8. if ([color=red]e.hash == hash && ((k = e.key) == key || key.equals(k)[/color])) {
  9. V oldValue = e.value;
  10. e.value = value;
  11. e.recordAccess(this);
  12. return oldValue;
  13. }
  14. }
  15. modCount++;
  16. addEntry(hash, key, value, i);
  17. return null;
      public V put(K key, V value) {
        if (key == null)
            return putForNullKey(value);
        int hash = hash(key.hashCode());
        int i = indexFor(hash, table.length);
        for (Entry<K,V> e = table[i]; e != null; e = e.next) {
            Object k;
            if ([color=red]e.hash == hash && ((k = e.key) == key || key.equals(k)[/color])) {
                V oldValue = e.value;
                e.value = value;
                e.recordAccess(this);
                return oldValue;
            }
        }

        modCount++;
        addEntry(hash, key, value, i);
        return null;
    }
    

红色部分对于重复对象的比较,使用了key的hashcode,key指向的地址,以及其值是否相等。
容量自增:
Java代码
  1. void resize(int newCapacity) {
  2. Entry[] oldTable = table;
  3. int oldCapacity = oldTable.length;
  4. if (oldCapacity == MAXIMUM_CAPACITY) {
  5. threshold = Integer.MAX_VALUE;
  6. return;
  7. }
  8. Entry[] newTable = new Entry[newCapacity];
  9. transfer(newTable);
  10. table = newTable;
  11. threshold = (int)(newCapacity * loadFactor);
  12. }
   void resize(int newCapacity) {
        Entry[] oldTable = table;
        int oldCapacity = oldTable.length;
        if (oldCapacity == MAXIMUM_CAPACITY) {
            threshold = Integer.MAX_VALUE;
            return;
        }

        Entry[] newTable = new Entry[newCapacity];
        transfer(newTable);
        table = newTable;
        threshold = (int)(newCapacity * loadFactor);
    }
   


Hashtable:
重量级,线程安全,不允许key或者value是null;
从源码可以看出与HashMap很相识,这是Hashmap为其轻量级的实现。
大量带有实际操作性的方法都为synchronized修饰。
Properties:Hashtable的子类,key和value都是String,同样为线程安全。
Java代码
  1. public synchronized Object setProperty(String key, String value) {
  2. return put(key, value);
  3. }
   public synchronized Object setProperty(String key, String value) {
        return put(key, value);
    } 
   

TreeMap:
集合是指一个对象可以容纳了多个对象(不是引用),这个集合对象主要用来管理维护一系列相似的对象。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值