List集合、Set集合、Map集合的简单介绍及实现原理

List集合

ArrayList、LinkedList、Vector这三个集合都实现了List集合接口,是有序集合,可以存储重复元素。

ArrayList集合

List集合是有序的,可以存放重复的元素,底层是通过一个动态数组来实现,默认长度为10,通过group方法扩容,每次扩容1.5倍。

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
        
private static final int DEFAULT_CAPACITY = 10;

private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

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);
    }

ArrayList接口实现了List集合,具有List集合的所有功能。实现了RandomAccess接口(随机访问),这个接口没有方法体,只是一个标记的作用,说明ArrayList集合的随机访问效率较高,因为ArrayList的底层是通过一个动态数组实现的,在访问的时候,可以直接通过索引获取对应的元素,但是在随机增删的时候效率较低,因为数组在内存中是连续的,在增删元素的时候,会判断容量是否够用,如果容量不足,会先扩容数组,其它位置的元素会相应的前移后移。

LinkedList集合

LinkedList集合是有序的,可以存放重复的元素,底层是通过一个双向链表来实现。

public class LinkedList<E>
    extends AbstractSequentialList<E>
    implements List<E>, Deque<E>, Cloneable, java.io.Serializable
    
transient Node<E> first;

transient Node<E> last;

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

LinkedList实现了Deque,即双端队列,支持在两端插入元素。LinkedList集合是通过双向链表实现的,所以该集合随机增删的速度较快,因为链表在内存中是不连续存在的,只需要在增删的时候改变指针指向的结点就可以了;但是随机查询的速度较慢,在使用get()方法查询时,会先判断该参数是否在链表中间位置之前或之后,然后在从头部向尾部或从尾部向头部依次查询,这样依次遍历就导致查询效率较低,在进行大量数据遍历的时通常使用迭代器遍历,会极大的提高查询速度。

Vector集合

public class Vector<E>
    extends AbstractList<E>
    implements List<E>, RandomAccess, Cloneable, java.io.Serializable

Vector集合在底层也是通过数组实现的,调用构造方法时的默认长度为10,通过grow方法实现扩容机制,每次的长度为原来的两倍,该集合的方法被synchronized关键字修饰,所以是线程安全的,但是效率有所降低。所以在单线程访问操作集合时,使用ArrayList集合,在多线程操作集合的时候使用Vector集合。

protected Object[] elementData;

public Vector() {this(10);}

private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
                                         capacityIncrement : oldCapacity);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        elementData = Arrays.copyOf(elementData, newCapacity);
    }
    
public synchronized boolean isEmpty() {
        return elementCount == 0;
    }
    
public synchronized void insertElementAt(E obj, int index) {
        modCount++;
        if (index > elementCount) {
            throw new ArrayIndexOutOfBoundsException(index
                                                     + " > " + elementCount);
        }
        ensureCapacityHelper(elementCount + 1);
        System.arraycopy(elementData, index, elementData, index + 1, elementCount - index);
        elementData[index] = obj;
        elementCount++;
    }

Set集合

public interface Set<E> extends Collection<E>

Set集合继承了Collection集合,Set的底层是通过红黑树实现的,不能存储重复元素,并且存储的元素也是无序的,Set集合没有索引,无法使用普通的for循环遍历。

HashSet

public class HashSet<E>
    extends AbstractSet<E>
    implements Set<E>, Cloneable, java.io.Serializable

实现了set集合,不能存储重复的元素,元素无序,底层是基于哈希表实现的。

public HashSet() {
        map = new HashMap<>();
    }
public HashSet(Collection<? extends E> c) {
        map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
        addAll(c);
    }   
         
发布了14 篇原创文章 · 获赞 0 · 访问量 804

猜你喜欢

转载自blog.csdn.net/weixin_43937112/article/details/103814664
今日推荐