Java in the container (collection)

1, Java common container: List, Set, Map

List:

  • Collection inherited interfaces (public interface List <E> extends Collection <E>), ordered and allowed duplicate values.

Set:

  • It inherited the Collection interface (public interface Set <E> extends Collection <E>), disorderly and does not allow duplicate values.

Map:

  • Is a key-value storage container (public interface Map <K, V>).

2, the difference between Collection and Collections

Collection:

  • Collection is a collection of classes common interface (Source: public interface Collection <E> extends Iterable <E>).
  • Can be found by looking at the source code, it contains are some common set of user interface, His immediate successors interfaces List and Set.

Collections:

  • Collections is a collection of tools (Source: public class Collections).
  • Which provides a series of operations on a collection of static methods, such as sorting: sort (), a collection of security: synchronizedCollection (), reverse: reverse () and so on.

3, the difference between ArrayList and LinkedList

ArrayList:

  • Underlying data structure is an array, more efficient query, delete added slowly (default to the end of the addition of the element at the specified location efficiency is relatively low, because of the need to specify the position of the following elements are shifted back).

LinkedList:

  • The underlying data structure is a doubly linked list (prev points to the former node, next point after the node) query efficiency is relatively slow, add and delete faster.

4, the difference between ArrayList and the Vector

ArrayList:

  • Non-thread-safe, high reading efficiency.

Vector:

  • (Display method of the class using the synchronized source code), the lower reading efficiency (recommended CopyOnWriteArrayList, the class for reading and writing little scenes) thread safe.

5, the difference between HashMap and Hashtable

HashMap:

  • Non thread-safe, to allow the empty key values, the efficiency is relatively high (the underlying data structure is an array using linked lists + + red-black tree (jdk8) + list or array (jdk7)).

Hashtable:

  • Thread safety, do not allow empty key, the efficiency is relatively low (recommended ConcurrentHashMap).

6, HashMap and TreeMap usage scenarios

HashMap:

  • Generally insertion, deletion, positioning of elements, use the HashMap (common).

TreeMap:

  • If you need an ordered set of recommended TreeMap.

7, HashMap implementation principle

To put operations as an example:

  • The first will be based on key hashCode hash value (section Source:? Return (key == null) 0: (h = key.hashCode ()) ^ (h >>> 16)), according to the hash worth to the elements in an array position (subscript), if the position of the element does not exist, then the element directly into this position; otherwise, determining whether the same element, if so, cover, or method to resolve the conflict using the fastener (creating a linked list, to join into the end of the chain, after the addition of the chain on the head, when more than 8, the use of red-black tree storage).
  • Put the key element is the inclusion of an element of, not just the only value.

8, HashSet implementation principle

To add operations as an example:

  • Add source into the (return map.put (e, PRESENT) == null), it can be seen that the underlying map is implemented, only the value passed as a Key map, and the map value using the unified PRESENT.

9, iterators: Iterator

Iterator:

  • Is a lightweight objects (created small price), mainly used to traverse the collection removing operation.
  • The following sample code
package com.spring.test.service.demo;

import java.util.*;

/**
 * @Author: philosopherZB
 * @Date: 2019/10/1
 */
public class Demo {
    public static void main(String[] args){
        List<String> list = new ArrayList<>(5);
        for(int i=0;i<5;i++){
            list.add("Test" + i);
            System.out.println("输入:Test" + i);
        }
        //利用iterator()返回一个Iterator对象
        Iterator<String> it = list.iterator();
        //判断是否还存在元素
        while(it.hasNext()){
            //第一次调用next()会返回集合中的第一个元素,之后返回下一个
            String s = it.next();
            if("Test3".equals(s))
                //移除某个元素
                it.remove();
        }
        list.forEach(l->{
            System.out.println(l);
        });
    }
}
View Code

10、ArrayList 扩容源码解析(JDK8)

源码解析:

  • 首先我们使用 ArrayList<String> list = new ArrayList<>(5)创建一个ArrayLsit,这表明创建的ArrayList初始容量为5.
  • 源码如下:
    //默认初始容量10
    private static final int DEFAULT_CAPACITY = 10;
    //一个空的默认对象数组,当ArrayList(int initialCapacity),ArrayList(Collection<? extends E> c)中的容量等于0的时候使用
    private static final Object[] EMPTY_ELEMENTDATA = {};
    //一个空的默认对象数组,用于ArrayList()构造器
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
    //一个对象数组,transient表示不能序列化
    transient Object[] elementData;
    //数组大小
    private int size;

    //以传入的容量构造一个空的list
    public ArrayList(int initialCapacity) {
        //如果传入值大于0,则创建一个该容量大小的数组。
        if (initialCapacity > 0) {
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
            //否则如果传入值等于0,则创建默认空数组
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            //如果小于0则抛出异常
            throw new IllegalArgumentException("Illegal Capacity: "+
                    initialCapacity);
        }
    }
  • 接着我们使用add方法添加一个字符串到该list中,list.add("Test")。进入add源码会发现,真正的扩容是发生在add操作之前的。
  • 源码如下:
    //默认添加在数组末尾
    public boolean add(E e) {
        //添加之前先确认是否需要扩容
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        //新加入的元素是添加在了数组的末尾,随后数组size自增。
        elementData[size++] = e;
        return true;
    }
  • 进入ensureCapacityInternal()方法查看对应源码如下:
    private void ensureCapacityInternal(int minCapacity) {
        //先通过calculateCapacity方法计算最终容量,以确认实际容量
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }
  • 到这一步,我们需要先进入calculateCapacity()方法看看他是如何计算最后容量的,源码如下:
    private static int calculateCapacity(Object[] elementData, int minCapacity) {
        //如果elementData为默认空数组,则比较传入值与默认值(10),返回两者中的较大值
        //elementData为默认空数组指的是通过ArrayList()这个构造器创建的ArrayList对象
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        //返回传入值
        return minCapacity;
    }
  • 现在我们确认了最终容量,那么进入ensureExplicitCapacity,查看源码如下:
    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;
        // overflow-conscious code
        //如果最终确认容量大于数组容量,则进行grow()扩容
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }
  • 可以看到,只有当最终容量大于数组容量时才会进行扩容。那么以我们上面的例子而言具体分析如下:
  • 首先因为我们创建的时候就赋了初始容量5,所以elementData.length = 5。
  • 当我们add第一个元素的时候,minCapacity是等于size + 1 = 1的。
  • 此时minCapacity - elementData.length > 0条件不成立,所以不会进入grow(minCapacity)方法进行扩容。
  • 以此类推,只有添加到第五个元素的时候,minCapacity = 6 大于 elementData.length = 5,这时就会进入grow(minCapacity)方法进行扩容。
  • grow()以及hugeCapacity()源码如下:
    //可分配的最大数组大小
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

    //扩容
    private void grow(int minCapacity) {
        // overflow-conscious code
        //oldCapacity表示旧容量
        int oldCapacity = elementData.length;
        //newCapacity表示新容量,计算规则为旧容量+旧容量的0.5,即旧容量的1.5倍。如果超过int的最大值会返回一个负数。
        //oldCapacity >> 1表示右移一位,对应除以2的1次方。
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        //如果新容量小于最小容量,则将最小容量赋值给新容量(有时手动扩容可能也会返回<0,对应方法为ensureCapacity())
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        //如果新容量大于MAX_ARRAY_SIZE,则执行hugeCapacity(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);
    }

    private static int hugeCapacity(int minCapacity) {
        //如果最小容量超过了int的最大值,minCapacity会是一个负数,此时抛出内存溢出错误
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        //比较最小容量是否大于MAX_ARRAY_SIZE,如果是则返回Integer.MAX_VALUE,否则返回MAX_ARRAY_SIZE
        return (minCapacity > MAX_ARRAY_SIZE) ?
                Integer.MAX_VALUE :
                MAX_ARRAY_SIZE;
    }

 (以上所有内容皆为个人笔记,如有错误之处还望指正。)

Guess you like

Origin www.cnblogs.com/xihuantingfeng/p/11616389.html