集合小结

来源:互联网 发布:动作片推荐 知乎 编辑:程序博客网 时间:2024/06/17 06:21

集合的分类

集合可分为两类,单列集合和双列集合。单列集合实现了Collection接口,直接实现Collection接口的有Set和List,实现了List接口的有ArrayList、LinkedList、Vector、Stack等,实现Set接口的有EnumSet、HashSet、TreeSet等。双列集合实现自Map接口,有HashMap、TreeMap、HashTable、Properties等。

接口简介

List

实现Collection接口,是有序的集合,数据存储和数据读取的顺序是一样的,不会给数据进行排序,允许有相同的元素

Set

实现Collection接口,是无序的集合,数据存储和数据读取的顺序是不一样的,会给数据进行排序,不允许有相同的元素

Map

是双列集合,存储的数据以key/value的形式存在

 

集合实现类详解

ArrayList

1、 是List接口的实现类,是线程异步的,是不安全的集合。

2、 实现了克隆、序列化接口和随机访问的接口,说明ArrayList的对象可以被克隆、可被转成字节流、查找数据时支持随机访问,因此ArrayList集合比较适合数据查询。以下是源码:

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

3、ArrayList集合内部封装的是一个object类型的数组,在不同版本的jdk中这个数组的初始化大小不同,有的是直接设置为10,有的是一个空的数组,我的jdk下的源码:

public ArrayList() {

        super();
        this.elementData = EMPTY_ELEMENTDATA;//一个空的数组
    }


4、 ArrayList下的数组使用transient修饰的,这表示集合被序列化时,没有数据的部分则不进行序列化

 private transient Object[] elementData;//使用transient修饰



5、因为ArrayList是封装了一个数组,所以当数据增多的时候就会出现数组扩容的情况,ArrayList中数组的长度会变成原来的150%,相当于增大了50%源码如下:

//添加数据
public boolean add(E e) {
        ensureCapacityInternal(size + 1);
        elementData[size++] = e;
        return true;
    }
    
//扩容方法
private void ensureCapacityInternal(int minCapacity) {
        if (elementData == EMPTY_ELEMENTDATA) {
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        ensureExplicitCapacity(minCapacity);
    }
    
private void ensureExplicitCapacity(int minCapacity) {
        modCount++;
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }
    
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);
        elementData = Arrays.copyOf(elementData, newCapacity);
    }


6、ArrayList中其他的方法无非用于对数据的增删查改,查询API即可使用

 

LinkedList


1、是List接口的实现类,是线程异步的,是不安全的集合。
2、实现了克隆、序列化接口和Deque的接口,说明LinkedList的对象可以被克隆、被转成字节流的、支持在两端插入和移除元素,定义了双端队列的操作。以下是源码:

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


3、LinkedList 是基于链表(维护了一个双向的循环链表)实现的,所以它比较适合进行插入和删除操作。
4、内部方法通过API很容易使用

HashMap

1、基于哈希表的 Map 接口的实现,数据以key-value的形式存储。

2、实现了克隆和序列化接口

   

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

public class HashMap<K,V>

   extends AbstractMap<K,V>

   implements Map<K,V>, Cloneable, Serializable

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

 

3、hashMap中有两个重要的参数:初始容量和加载因子,用来初始化哈希表中数组的长度和衡量数组是否应该扩容的一个标准

4、添加方法,HashMap是可以插入null作为key的,添加流程很清晰,如果两个key相同,则后一个的value会将前一个value覆盖掉

   

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

public V put(K key, V value) {

       if (table == EMPTY_TABLE) {

           inflateTable(threshold);

       }

       if (key == null)

           return putForNullKey(value);

       int hash = hash(key);

       int i = indexFor(hash, table.length);

       for (Entry<K,V> e = table[i]; e != null; e = e.next) {

           Object k;

           if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {

                V oldValue = e.value;

                e.value = value;

                e.recordAccess(this);

                return oldValue;

           }

       }

 

       modCount++;

       addEntry(hash, key, value, i);

       return null;

    }

 

   private V putForNullKey(V value) {

       for (Entry<K,V> e = table[0]; e != null; e = e.next) {

           if (e.key == null) {

                V oldValue = e.value;

                e.value = value;

                e.recordAccess(this);

                return oldValue;

           }

        }

       modCount++;

       addEntry(0, null, value, 0);

       return null;

    }

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

 

5、扩容机制:初始化的容量是16,然后根据加载因子通过判断进行扩容,将散列表中数组的长度变成原来的两倍

   

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// HashMap初始容量大小16

static final int DEFAULT_INITIAL_CAPACITY =1 << 4;     

 

 

void addEntry(int hash, K key, V value, intbucketIndex) {

       if ((size >= threshold) && (null != table[bucketIndex])) {

           resize(2 * table.length);

           hash = (null != key) ? hash(key) : 0;

           bucketIndex = indexFor(hash, table.length);

       }

 

       createEntry(hash, key, value, bucketIndex);

    }

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

 

6、HashMap是线程不安全   

7、内部方法通过API很容易使用

HashTable

1、继承自Dictionary,克隆接口和序列化接口

   

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

public class Hashtable<K,V>

   extends Dictionary<K,V>

    implementsMap<K,V>, Cloneable, java.io.Serializable

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

 

2、HashTable中的用于操作集合的公共方法都用synchronized修饰的,是线程安全的

3、添加方法:不允许null作为value,null作为key也是不允许的,如果两个key相同,则后一个的value会将前一个value覆盖掉

   

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

public synchronized V put(K key, V value) {

       if (value == null) {

           throw new NullPointerException();

       }

 

       // Makes sure the key is not already in the hashtable.

       Entry tab[] = table;

       //通过key计算hash值

       int hash = hash(key);

       //通过hash值计算所在的具体位置的下标

       int index = (hash & 0x7FFFFFFF) % tab.length;

       //遍历集合

       for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {

           //如果在相同的位置存在相同的key值,则将之前的值覆盖掉           

           if ((e.hash == hash) && e.key.equals(key)) {

                V old = e.value;

                e.value = value;

                return old;

           }

       }

 

       modCount++;

       //散列表如果超过阈值则进行扩容

       if (count >= threshold) {

           // Rehash the table if the threshold is exceeded

           rehash();

 

           tab = table;

           hash = hash(key);

           index = (hash & 0x7FFFFFFF) % tab.length;

       }

 

       // Creates the new entry.

       Entry<K,V> e = tab[index];

       tab[index] = new Entry<>(hash, key, value, e);

       count++;

       return null;

    }

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

 

4、扩容机制:将数组长度变成原来的两倍,然后加1

   

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

protected void rehash() {

       int oldCapacity = table.length;

       Entry<K,V>[] oldMap = table;

 

       // 增大两倍,然后+1

       int newCapacity = (oldCapacity << 1) + 1;

       if (newCapacity - MAX_ARRAY_SIZE > 0) {

           if (oldCapacity == MAX_ARRAY_SIZE)

                // Keep running with MAX_ARRAY_SIZEbuckets

                return;

           newCapacity = MAX_ARRAY_SIZE;

       }

       Entry<K,V>[] newMap = new Entry[newCapacity];

 

       modCount++;

       threshold = (int)Math.min(newCapacity * loadFactor, MAX_ARRAY_SIZE + 1);

       boolean rehash = initHashSeedAsNeeded(newCapacity);

 

       table = newMap;

 

       for (int i = oldCapacity ; i-- > 0 ;) {

           for (Entry<K,V> old = oldMap[i] ; old != null ; ) {

                Entry<K,V> e = old;

                old = old.next;

 

                if (rehash) {

                    e.hash = hash(e.key);

                }

                int index = (e.hash &0x7FFFFFFF) % newCapacity;

                e.next = newMap[index];

                newMap[index] = e;

           }

        }

    }

Vector

1、与ArrayList实现的接口一致

   

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

public class Vector<E>

      extends AbstractList<E>

      implements List<E>, RandomAccess, Cloneable, java.io.Serializable

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

 

2、底层封装一个数组,初始的大小是10  

3、扩容机制:扩大一倍

   

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

public synchronized boolean add(E e) {

       modCount++;

       ensureCapacityHelper(elementCount + 1);

       elementData[elementCount++] = e;

       return true;

    }

   

 

private void ensureCapacityHelper(intminCapacity) {

       // overflow-conscious code

       if (minCapacity - elementData.length > 0)

           grow(minCapacity);

    }

   

 

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

    }

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

 

这只是一部分常用的集合,还有HashSet、TreeMap、TreeSet等集合