• Java Collection


    三、  Java Collection

    1.  Collection 接口

    // Collection 接口在其源码中的定义:
     * 1. Collection 是集合层次结构中的根接口
     * 2. 一个 Collection 代表 一组对象(objects),这些对象称为其元素(elements)
     * 3. 一些 Collection 允许有重复的元素,而另一些 Collection 不允许有重复的元素
     * 4. 一些 Collection 的元素是有序的,而另一些 Collection 是无序的
     * 5. JDK 没有提供任何直接(direct)实现 Collection 的类
     * 6. JDK 只提供了继承 Collection 的“子接口”(List 和 Set)的实现类
    
     * -Set 中的元素没有顺序且不可以重复
     * -List 中的元素有顺序且可以重复
     * -Map 接口定义了存储 “键(key)- 值(value)映射对” 的方法,键(key)不能重复,重写 hashCode() 和 equals() 方法!
     * 
     *      * 接口             Collection
     *                        /        
     *      * 接口           Set        List               Map
     *                       |        /                   |
     *      * 类         HashSet  ArrayList LinkedList    HashMap
    
    // 谈到 Collection 接口,我们不得不区别一下 Collections 类
    // Collections 是一个类,不能实例化,是一个工具类,它包含各种有关集合操作的静态(static)多态方法,比如 sort、search、shuffle 以及线程安全等操作
    public class Collections {
        // 私有化构造器,所以不能被实例化
        private Collections() {
        }
        ...
    }

     

    2.  ArrayList

    1. ArrayList 是 List 接口的实现类,并继承于 AbstractList(AbstractList 继承于 AbstractCollection,并且实现了大部分 List 接口)
    2. ArrayList 的底层实现是动态数组(属于数据结构中的可扩容的线性表),线程不安全,效率高
    
    // 创建
    List list = new ArrayList();
    
    // 常用方法
    list.size();// 返回元素的数量
    list.isEmpty();
    list.add(element);
    list.add(index, element);// 在指定位置添加元素
    list.remove(index);// 删除指定索引的元素,并返回该元素内容
    list.remove(element);// 删除指定元素,删除成功返回 true
    list.get(index);// 获取指定位置的元素
    list.toArray();// 返回一个包含列表中的所有元素的数组
    list.contains(element);// 判断是否包含指定元素
    list.indexOf(element);// 返回指定元素所在的第一个位置,没找到返回 -1
    list.lastIndexOf(element);// 返回指定元素所在的最后一个位置
    list.clear();// 删除所有元素
    
    // 为了更深入了解 ArrayList,我们来分析一下 ArrayList 的部分源码  
    public class ArrayList<E> extends AbstractList<E>
            implements List<E>, RandomAccess, Cloneable, java.io.Serializable
    {
        private static final int DEFAULT_CAPACITY = 10;// 默认容量为 10
        private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;// 最大容量
        private static final Object[] EMPTY_ELEMENTDATA = {};
        private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
    
        transient Object[] elementData;// 可见底层是 Object 对象数组
        private int size;// 包含元素的数量
    
        // 无参构造器,对象数组默认为空
        public ArrayList() {
            this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
        }
    
        // 有参构造器,用于初始化数组容量
        public ArrayList(int initialCapacity) {
            if (initialCapacity > 0) {
                this.elementData = new Object[initialCapacity];
            } else if (initialCapacity == 0) {
                this.elementData = EMPTY_ELEMENTDATA;
            } else {
                throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity);
            }
        }
    
        // 返回所包含元素的数量
        public int size() {
            return size;
        }
    
        // 判断对象数组是否为空
        public boolean isEmpty() {
            return size == 0;
        }
    
        // 返回一个包含列表中的所有元素的数组
        public Object[] toArray() {
            return Arrays.copyOf(elementData, size);
        }
        
        // 删除元素
        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;
            return oldValue;
        }
    
        // 添加元素
        public boolean add(E e) {
            ensureCapacityInternal(size + 1);// 判断是否需要扩容
            elementData[size++] = e;
            return true;
        }
    
        // 判断是否需要扩容
        private void ensureCapacityInternal(int minCapacity) {
            if (elementData == DEFAULTCAPACITY_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) {
            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);
        }
        private static int hugeCapacity(int minCapacity) {
            if (minCapacity < 0)
                throw new OutOfMemoryError();
            return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE;
        }
        ...
     } 
    ArrayList

    3.  LinkedList

    1. LinkedList 是 List 接口的实现类,并继承于 AbstractSequentialList(AbstractSequentialList 继承于 AbstractList,提供了对数据元素的链式访问而不是随机访问)
    2. LinkedList 的底层实现是链表(属于数据结构中的双向链表),线程不安全,效率高
    
    // 创建
    List link = new LinkedList();
    
    // 常用方法
    link.size();
    link.getFirst();// 返回第一个节点的元素
    link.getLast();// 返回最后一个节点的元素
    link.get(index);// 返回指定位置的元素
    link.contain(element);// 判断链表中是否有指定元素
    link.addFirst(element);// 从链表头部插入元素,无返回值
    link.add(element); // 从链表尾部插入元素,插入成功返回 true
    link.add(index, element);// 在指定位置插入元素,无返回值
    link.remove(element); // 删除指定元素,删除成功返回 true
    link.remove(index);// 删除指定位置的元素,删除成功返回被删除元素
    link.addAll(Collection);// 添加指定集合
    link.clear();// 清空链表,释放节点空间
    
    // 为了更深入了解 LinkedList,我们来分析一下 LinkedList 的部分源码
    public class LinkedList<E>
        extends AbstractSequentialList<E>
        implements List<E>, Deque<E>, Cloneable, java.io.Serializable
    {   
        // 用私有静态内部类定义链表的节点对象
        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;
            }
        }
    
        transient int size = 0;// 元素的数量
        transient Node<E> first;// 指向链表的第一个节点
        transient Node<E> last;// 指向链表的最后一个节点
       
        public LinkedList() {
        }
    
        // 有参构造器,用于构造包含指定集合的链表
        public LinkedList(Collection<? extends E> c) {
            this();
            addAll(c);// 添加指定集合
        }
        // 返回元素的数量
        public int size() {
            return size;
        }
    
        // 在链表的头部插入元素
        public void addFirst(E e) {
            linkFirst(e);
        }
        private void linkFirst(E e) {
            final Node<E> f = first;
            final Node<E> newNode = new Node<>(null, e, f);
            first = newNode;
            if (f == null)
                last = newNode;
            else
                f.prev = newNode;
            size++;
            modCount++;
        }
    
        // 在链表的尾部插入元素
        public boolean add(E e) {
            linkLast(e);
            return true;
        }
        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++;
        }
        
        // 删除元素
        public boolean remove(Object o) {
            if (o == null) {
                for (Node<E> x = first; x != null; x = x.next) {
                    if (x.item == null) {
                        unlink(x);
                        return true;
                    }
                }
            } else {
                for (Node<E> x = first; x != null; x = x.next) {
                    if (o.equals(x.item)) {
                        unlink(x);
                        return true;
                    }
                }
            }
            return false;
        }
        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;
        }
        
        // 清空链表
        public void clear() {
            for (Node<E> x = first; x != null; ) {
                Node<E> next = x.next;
                x.item = null;
                x.next = null;
                x.prev = null;
                x = next;
            }
            first = last = null;
            size = 0;
            modCount++;
        }
    }
    LinkedList

    4.  HashMap

    1. HashMap 是 Map 接口的实现类,并继承于 AbstractMap(AbstractMap 是 Map 接口的抽象实现类,并且实现了大部分 Map 接口)
    2. HashMap 的底层实现:哈希表+链表(属于数据结构中的邻接表)
    
    // 创建
    Map map = new HashMap();
    
    // 常用方法
    map.put(k,v);// 添加键值对,如果 key 已存在,则覆盖 value,并返回被覆盖的 value;不存在,则返回 null
    map.putAll(map02);// 添加指定的 map 集合
    map.remove(k);// 删除指定 key 的节点,并返回 value
    map.get(k);// 获取指定 key 的 value
    map.containsKey(k);// 判断是否含有指定 key 的节点
    map.containsValue(v);// 判断是否含有指定 value 的节点
    map.size();// 返回键值对的数量
    map.values();//获取所有 value,返回值类型 Collection<valueType>
    map.keySet(); //获取所有 key,返回值类型 Set<keyType>
    map.entrySet();// 获取所有 key 和 value,返回值类型 Set<Entry<keyType, valueType>>
    map.clear();// 清空 map 里的所有键值对
    
    // 为了更深入了解 HashMap,我们来分析一下 HashMap 的部分源码
    public class HashMap<K,V> extends AbstractMap<K,V>
        implements Map<K,V>, Cloneable, Serializable {
    
        static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;// 默认最小容量 MUST be a power of two. aka 16
        static final int MAXIMUM_CAPACITY = 1 << 30;// 默认最大容量
        static final float DEFAULT_LOAD_FACTOR = 0.75f;// 默认负载因子
    
        // 用静态内部类定义链表的节点对象
        static class Node<K,V> implements Map.Entry<K,V> {
            final int hash;// 存放 hashCode
            final K key;// 存放 key
            V value; // 存放 value
            Node<K,V> next;// 指向下个节点
            
            // 有参构造器
            Node(int hash, K key, V value, Node<K,V> next) {
                this.hash = hash;
                this.key = key;
                this.value = value;
                this.next = next;
            }
    
            public final K getKey()        { return key; }
            public final V getValue()      { return value; }
            public final String toString() { return key + "=" + value; }
            
            /* 使用自己定义的 hashCode()方法
               这里给出 java.util.Objects 中定义的 hashCode()方法
               public static int hashCode(Object o) {
                   return o != null ? o.hashCode() : 0;
               }
            */
            public final int hashCode() {
                return Objects.hashCode(key) ^ Objects.hashCode(value);
            }
             
            public final V setValue(V newValue) {
                V oldValue = value;
                value = newValue;
                return oldValue;
            }
    
            /* 使用自己定义的 equals()方法
               这里给出 java.util.Objects 中定义的 equals()方法
               public static boolean equals(Object a, Object b) {
                   return (a == b) || (a != null && a.equals(b));
               }
            */ 
            public final boolean equals(Object o) {
                if (o == this)
                    return true;
                if (o instanceof Map.Entry) {
                    Map.Entry<?,?> e = (Map.Entry<?,?>)o;
                    if (Objects.equals(key, e.getKey()) && Objects.equals(value, e.getValue()))
                        return true;
                }
                return false;
            }
        }
     
        transient Node<K,V>[] table;// 声明哈希表
        transient int size;// 元素的数量
        final float loadFactor;// 负载因子
        
        // 无参构造器
        public HashMap() {
            this.loadFactor = DEFAULT_LOAD_FACTOR;
        }
        
        public int size() {
            return size;
        }
        
        public boolean isEmpty() {
            return size == 0;
        }
        
        // 定义了自己的 hash()方法
        static final int hash(Object key) {
            int h;
            return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
        }
    
        /* 添加键值对
           我们先在这给出 java.lang.Object 的 equals()方法
           public boolean equals(Object obj) {
               return (this == obj);
           }
           所以,我们在做 key 的比较时,要根据自己的需求重写 equals()方法 
        */
        public V put(K key, V value) {
            return putVal(hash(key), key, value, false, true);
        }
        final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                       boolean evict) {
            Node<K,V>[] tab;
            Node<K,V> p;
            int n, i;
            // 如果哈希表为空,初始化哈希表
            if ((tab = table) == null || (n = tab.length) == 0)
                n = (tab = resize()).length;
            // 如果 hash(key) 对应哈希表位置为 null,直接存放该节点
            if ((p = tab[i = (n - 1) & hash]) == null)
                tab[i] = newNode(hash, key, value, null);
            else {
                Node<K,V> e; K k;
                // 如果 hash(key) 对应哈希表位置存放的节点 key 等于 我们要添加的键值对的 key,则直接覆盖 value
                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);
                // 如果 hash(key) 对应哈希表位置存放的节点 key 不等于 我们要添加的键值对的 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;
                    }
                }
                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;
        }
        
        // 有参构造器,使用与指定的 Map 相同的映射,构造一个新的 HashMap,新的 HashMap 内包含了指定 map 的所有元素
        public HashMap(Map<? extends K, ? extends V> m) {
            this.loadFactor = DEFAULT_LOAD_FACTOR;
            putMapEntries(m, false);
        }
        final void putMapEntries(Map<? extends K, ? extends V> m, boolean evict) {
            int s = m.size();
            if (s > 0) {
                if (table == null) { // pre-size
                    float ft = ((float)s / loadFactor) + 1.0F;
                    int t = ((ft < (float)MAXIMUM_CAPACITY) ? (int)ft : MAXIMUM_CAPACITY);
                    if (t > threshold)
                        threshold = tableSizeFor(t);
                }
                else if (s > threshold)
                    resize();
                for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) {
                    K key = e.getKey();
                    V value = e.getValue();
                    putVal(hash(key), key, value, false, evict);
                }
            }
        }
    
        // 获取指定 key 的 value
        public V get(Object key) {
            Node<K,V> e;
            return (e = getNode(hash(key), key)) == null ? null : e.value;
        }
        final Node<K,V> getNode(int hash, Object key) {
            Node<K,V>[] tab; 
            Node<K,V> first, e; 
            int n; 
            K k;
            if ((tab = table) != null && (n = tab.length) > 0 &&
                (first = tab[(n - 1) & hash]) != null) {
                if (first.hash == hash && // always check first node
                    ((k = first.key) == key || (key != null && key.equals(k))))
                    return first;
                if ((e = first.next) != null) {
                    if (first instanceof TreeNode)
                        return ((TreeNode<K,V>)first).getTreeNode(hash, key);
                    do {
                        if (e.hash == hash &&
                            ((k = e.key) == key || (key != null && key.equals(k))))
                            return e;
                    } while ((e = e.next) != null);
                }
            }
            return null;
        }
        
        // 是否存在指定 key
        public boolean containsKey(Object key) { 
            return getNode(hash(key), key) != null; 
        }
        
        // 删除指定 key 的键值对,并返回 value
        public V remove(Object key) {
            Node<K,V> e;
            return (e = removeNode(hash(key), key, null, false, true)) == null ? null : e.value;
        }
        final Node<K,V> removeNode(int hash, Object key, Object value,
                                   boolean matchValue, boolean movable) {
            Node<K,V>[] tab; 
            Node<K,V> p; 
            int n, index;
            if ((tab = table) != null && (n = tab.length) > 0 && (p = tab[index = (n - 1) & hash]) != null) {
                Node<K,V> node = null, e; 
                K k; 
                V v;
                if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k))))
                    node = p;
                else if ((e = p.next) != null) {
                    if (p instanceof TreeNode)
                        node = ((TreeNode<K,V>)p).getTreeNode(hash, key);
                    else {
                        do {
                            if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) {
                                node = e;
                                break;
                            }
                            p = e;
                        } while ((e = e.next) != null);
                    }
                }
                if (node != null && (!matchValue || (v = node.value) == value || (value != null && value.equals(v)))) {
                    if (node instanceof TreeNode)
                        ((TreeNode<K,V>)node).removeTreeNode(this, tab, movable);
                    else if (node == p)
                        tab[index] = node.next;
                    else
                        p.next = node.next;
                    ++modCount;
                    --size;
                    afterNodeRemoval(node);
                    return node;
                }
            }
            return null;
        }
        
        // 清空
        public void clear() {
            Node<K,V>[] tab;
            modCount++;
            if ((tab = table) != null && size > 0) {
                size = 0;
                for (int i = 0; i < tab.length; ++i)
                    tab[i] = null;
            }
        }
    }
    HashMap

    5.  HashSet

    1. HashSet 是 Set 接口的实现类,并继承于 AbstractSet(AbstractSet 继承于 AbstractCollection,并且实现了大部分 Set 接口)
    2. HashSet 的底层实现:利用 “HashMap 键唯一” 的特性
    
    // 创建
    Set set = new HashSet();
    
    // 常用方法
    set.size();// 返回元素的数量
    set.isEmpty();
    set.add(e);// 添加元素,添加成功返回 true,否则返回 false
    set.remove(e);// 删除指定元素,删除成功返回 true
    set.contains(e);// 判断指定元素是否已存在
    set.clear();// 清空 set 里的所有元素
    
    // 为了更深入了解 HashSet,我们来分析一下 HashSet 的部分源码
    public class HashSet<E>
        extends AbstractSet<E>
        implements Set<E>, Cloneable, java.io.Serializable
    {
        private transient HashMap<E,Object> map;// 哇,直接就用了 HashMap
    
        private static final Object PRESENT = new Object();// 创建一个 Object 对象常量,其实就是用来填充 HashMap 的 value
    
        public HashSet() {
            map = new HashMap<>();
        }
    
        public int size() {
            return map.size();
        }
    
        public boolean isEmpty() {
            return map.isEmpty();
        }
    
        public boolean contains(Object o) {
            return map.containsKey(o);
        }
    
        public boolean add(E e) {
            // 当添加元素 e 已经存在时,即对应的 map 里的 key 存在,则 map 的 put()方法会返回被覆盖的 value,这个 value 就是 PRESENT,不等于 null,故返回 false
            return map.put(e, PRESENT)==null;
        }
    
        public boolean remove(Object o) {
            return map.remove(o)==PRESENT;
        }
    
        public void clear() {
            map.clear();
        }
    }
    HashSet

    6.  Iterator 迭代器

    1.所有实现了 Collection 接口的容器类都有一个 iterator() 方法,用来返回一个实现了 Iterator 接口的对象
    2.迭代器使遍历操作更加方便
    3.java.util.Iterator 接口定义了如下方法:
     * boolean hasNext();// 判断是否有下一个节点
     * Object next();// 返回游标(cursor)当前位置的元素,并且游标(cursor)指向下一个位置
     * void remove();// 删除游标左边(lastRet)的元素,在执行完 next()方法 之后该操作只能执行一次,因为每次执行 remove()方法后 lastRet 都会置为 -1;只有当再次使用 next()方法后,才会给 lastRet 重新赋值
    
    // 下面给出 ArrayList 的遍历操作,LinkedList、HashMap、HashSet 的遍历操作都类似,需要注意的是 Map 和 Set 是用 哈希表+链表 实现的,所以不能使用第一种遍历方式(索引遍历)
    public class Traversal {
        public static void main(String[] args) {
            List<String>  list = new ArrayList<>();
            list.add("aaa");
            list.add("bbb");
            list.add("ccc");
            
            //遍历方式一
            for(int i=0;i<list.size();i++)
                System.out.println(list.get(i));
            
            //遍历方式二
            for(String li : list)
                System.out.println(li);
            
            //遍历方式三
            for(Iterator<String> iterator = list.iterator();iterator.hasNext();)
                System.out.println(iterator.next());
            
            //遍历方式四
            Iterator<String> iterator = list.iterator();
            while(iterator.hasNext())
                System.out.println(iterator.next());
        }
    }

     

  • 相关阅读:
    bzoj4105: [Thu Summer Camp 2015]平方运算
    bzoj4035: [HAOI2015]数组游戏
    bzoj1022: [SHOI2008]小约翰的游戏John
    bzoj4665: 小w的喜糖
    CodeChef:Little Elephant and Colored Coins
    bzoj4664: Count
    bzoj4498: 魔法的碰撞
    bzoj4230: 倒计时
    bzoj4532: [BeiJing2014 WinterCamp] 珠链
    python 画正态曲线
  • 原文地址:https://www.cnblogs.com/IT-LFP/p/10965611.html
Copyright © 2020-2023  润新知