Java-集合、Map-1-随笔

Collection集合

结构

Collection 接口的接口 对象的集合(单列集合)
├——-List 接口:元素按进入先后有序保存,可重复
│—————-├ LinkedList 接口实现类, 链表, 插入删除, 没有同步, 线程不安全
│—————-├ ArrayList 接口实现类, 数组, 随机访问, 没有同步, 线程不安全
│—————-└ Vector 接口实现类 数组, 同步, 线程安全
│ ———————-└ Stack 是Vector类的实现类
└——-Set 接口: 仅接收一次,不可重复,并做内部排序
├—————-└HashSet 使用hash表(数组)存储元素
│————————└ LinkedHashSet 链表维护元素的插入次序
└ —————-TreeSet 底层实现为二叉树,元素排好序

Map 接口 键值对的集合 (双列集合)
├———Hashtable 接口实现类, 同步, 线程安全
├———HashMap 接口实现类 ,没有同步, 线程不安全-
│—————–├ LinkedHashMap 双向链表和哈希表实现
│—————–└ WeakHashMap
├ ——–TreeMap 红黑树对所有的key进行排序
└———IdentifyHashMap

2

2

Collection接口实现类的特点

  1. public interface Collection<E> extends Iterable<E>
    
  2. Collection 实现子类可以存放多个元素,每个元素可以是Object

  3. 常用方法,以实现子类ArrayList来演示:

    • add():添加指定元素
    • remove():删除指定元素,可以按照index 或 object,按照object时会顺序查找,并删除找到的第一个object
    • contains():查找元素是否存在,参数object
    • size():获取元素个数
    • isEmpty():判空
    • clear():清空
    • addAll():添加多个元素,参数一个collcetion对象
    • containAll():查找多个元素是否存在,只有所有的元素都存在,才返回true,否则false,参数一个collcetion对象
    • removeAll(): 删除多个元素,只要有一个元素能被删除掉,就返回true,一个都没被删除时,才返回false,参数一个collcetion对象
  4. Collection接口遍历元素方式

    1. 使用Iterator(迭代器)

      • )Iterator对象称为迭代器,主要用于遍历Collection集合中的元素
      • )所有实现了Collection几口的集合类都有一个iterator()方法,用以返回一个实现了Iterator接口的对象,即可以返回一个迭代器
      • )Iterator仅用于遍历集合,Iterator本身并不存放对象
        在这里插入图片描述
    2. iterator对象 .iterator():返回该collection的迭代器

List

  1. List接口基本介绍

    • List接口是 Collection 接口的子接口List .java

    • List集合类中元素有序(即添加顺序和取出顺序一致)、且可重复。List集合中的每个元素都有其对应的顺序索引,即支持索引。(所以遍历List的时候可以用迭代器,for each,和for i 索引进行遍历)

    • List容器中的元素都对应一个整数型的序号记载其在容器中的位置,可以根据序号存取容器中的元素

    • JDK API中List接口的实现类有:

      AbstractList , AbstractsequentialList , ArrayList , AttributeList , CopyOnwriteArrayList ,LinkedList ,RoleList , RoleUnresolvedList , stack , Vector

  2. List常用方法:

    • void add(int index, Object ele):在index位置插入ele元素,不加index参数的话,默认加在最后位置
    • boolean addAll(int index, Collection eles):从index位置开始讲eles中的所有元素添加进来
    • Object get(int index):获取指定元素位置
    • int indexOf(Object obj):获取第一次出现该obj的index
    • int lastIndexOf(Object obj):返回List中末次出现obj的index
    • Object remove(int index):移除指定位置的obj
    • Object set(int index, Object ele):设置指定index位置的元素ele,相当于是替换,并返回index处的ele1
    • List subList(int fromIndex, int toIndex):返回从fromIndex到toIndex位置的子集合,范围前闭后开为 [ fromIndex, toIndex ),总个数 toIndex - fromIndex

ArrayList

ArrayList注意事项
  1. ArrayList 可以加入null,并且可以多个null
  2. ArrayList是由数组来实现数据存储的
  3. ArrayList基本等同于Vector,除了ArrayList是线程不安全(执行效率高). 方法没有synchronized修饰
  4. 线程不安全,在多线程情况下,不建议使用ArrayList
源码分析:
  1. ArrayList中维护了一个Object类型的数组elementData.
    transient Object[] elementData;

  2. 当创建Arraylist对象时,如果使用的是无参构造器,则初始elementData容量为0,第1次添加元素,则将elementData的容量扩为10, 如需要再次扩容,则扩容为elementData当前容量的1.5倍。(源码判断当前容量为0时,新建一个默认大小的数组,而默认大小DEFAULT_CAPACITY是被final修饰定义的int 10,若扩容时,当前容量不为0,则扩容1.5倍,并将旧数据copy到新的数组里面。当然,这也说明如果刚开始new ArrayList对象的时候,如果传给构造器有初始容量且大于0,那么第一次扩容,就会按照1.5倍进行扩容,但同时,每次扩容容量至少增加1个容量。如:初始的设置容量为1,那么添加第二个元素时,1 + 1>>1 = 1,1 - 1 = 0按1.5倍计算,就算出需要扩充的容量为0,这时候0是小于minCapacity - OldCapacity的,所以按最小扩容1个容量,去扩容)

    //扩容源码 JDK14
    
    //minCapacity的实参为 size + 1(当前已经存储的元素个数 + 1)
    private Object[] grow(int minCapacity) {
            int oldCapacity = elementData.length;
            if (oldCapacity > 0 || elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
                int newCapacity = ArraysSupport.newLength(oldCapacity,
                        minCapacity - oldCapacity, /* minimum growth */
                        oldCapacity >> 1           /* preferred growth */);
                return elementData = Arrays.copyOf(elementData, newCapacity);
            } else {
                return elementData = new Object[Math.max(DEFAULT_CAPACITY, minCapacity)];
            }
        }
    
     //ArraysSupport.newLength()
     public static int newLength(int oldLength, int minGrowth, int prefGrowth) {
         // assert oldLength >= 0
         // assert minGrowth > 0
    
         int newLength = Math.max(minGrowth, prefGrowth) + oldLength;
         if (newLength - MAX_ARRAY_LENGTH <= 0) {
             return newLength;
         }
         return hugeLength(oldLength, minGrowth);
     }
    
  3. 如果使用的是指定大小的构造器,则初始elementData容量为指定大小,如果需要扩容,则直接扩容elementData为1.5倍

Vector

  1. Vector类的定义说明
    public class vector<E>extends AbstractList<E>
    implements List<E>,RandomAccess,cloneable,serializable

  2. Vector底层也是一个对象数组,protected Objectl] elementData;

  3. Vector是线程同步的,即线程安全, Vector类的操作方法带有synchronized

    public synchronized E get(int index) {
        //synchronized 有synchronized修饰
    	if (index >= elementCount)
    		throw new ArraylndexOutOfBoundsException(index);
        return elementData(index);
    }
    
  4. 在开发中,需要线程同步安全时,考虑使用Vector

  5. 默认容量大小

    通过第三个构造函数,可以看出,无参的话,默认设置初始容量为10

    //源码 JDK14
    
    public Vector(int initialCapacity, int capacityIncrement) {
        //initialCapacity: 初始容量
        //capacityIncrement:每次扩容时,扩容多大(但实际扩容这个值只是用来参考,并不一定真的就扩容这么大,下面扩容部分能详细看到)
            super();
            if (initialCapacity < 0)
                throw new IllegalArgumentException("Illegal Capacity: "+
                                                   initialCapacity);
            this.elementData = new Object[initialCapacity];
            this.capacityIncrement = capacityIncrement;
        }
    
        /**
         * Constructs an empty vector with the specified initial capacity and
         * with its capacity increment equal to zero.
         *
         * @param   initialCapacity   the initial capacity of the vector
         * @throws IllegalArgumentException if the specified initial capacity
         *         is negative
         */
    public Vector(int initialCapacity) {
    		this(initialCapacity, 0);
        }    
    
        /**
         * Constructs an empty vector so that its internal data array
         * has size {@code 10} and its standard capacity increment is
         * zero.
         */
    public Vector() {
    		this(10);
    	}    
    
  6. 扩容源码

    //源码 JDK14
    //扩容首先在这个无参函数进去,然后调下面有参数的grow函数
    private Object[] grow() {
            return grow(elementCount + 1);
        }
    
    private Object[] grow(int minCapacity) {
            int oldCapacity = elementData.length;
            int newCapacity = ArraysSupport.newLength(oldCapacity,
                    minCapacity - oldCapacity, /* minimum growth */
                    //这里看出来,它会将 "扩容一倍所能增加的容量(也就是oldCapacity)"和
                    // "设置的固定扩容大小" 进行比较,谁大则用谁做参数传进去
                    capacityIncrement > 0 ? capacityIncrement : oldCapacity
                                               /* preferred growth */);
            return elementData = Arrays.copyOf(elementData, newCapacity);
        }
    
    
    //ArraysSupport 类的静态方法
    //这里主要处理   扩容量完有可能超过了最大阈值的情况   和   扩容增加的容量未超过1
    public static int newLength(int oldLength, int minGrowth, int prefGrowth) {
            // assert oldLength >= 0
            // assert minGrowth > 0
    
            int newLength = Math.max(minGrowth, prefGrowth) + oldLength;
            if (newLength - MAX_ARRAY_LENGTH <= 0) {
                return newLength;
            }
            return hugeLength(oldLength, minGrowth);
        }
    
    private static int hugeLength(int oldLength, int minGrowth) {
            int minLength = oldLength + minGrowth;
            if (minLength < 0) { // overflow
                throw new OutOfMemoryError("Required array length too large");
            }
            if (minLength <= MAX_ARRAY_LENGTH) {
                return MAX_ARRAY_LENGTH;
            }
            return Integer.MAX_VALUE;
        }
    
  7. Vector与ArrayList对比

底层结构版本线程安全(同步)效率扩容倍数
ArrayList可变数组jdk1.2开始有不安全,效率高如果有参构造,则扩容1.5倍,如果是无参,第一次扩容10,后面扩容1.5倍
Vector可变数组jdk1.0开始有安全,效率不高如果有参构造,指定大小,则扩容(2倍和增长capacityIncrement)较大的哪个,如果是无参,默认初始容量10,满了以后,按(2倍和增长capacityIncrement较大的那个)扩容

LinkedList

特点:
  1. LinkedList底层实现了双向链表和双端队列特点
  2. 可以添加任意元素(元素可以重复),包括null
  3. 线程不安全,没有实现同步
底层结构:
  1. LinkedList底层维护了一个双向链表.

  2. LinkedList中维护了两个属性first和last分别指向首节点和尾节点

  3. 每个节点(Node对象),里面又维护了prev、next、item三个属性,其中通过prev指向前一个,通过next指向后一个节点。最终实现双向链表.

  4. LinkedList的元素的添加和删除,不是通过数组完成的(因为删除元素只需要动其中的需要删除的节点,后不需要移位其他元素),相对来说效率较高。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JrlF1oeG-1646660444022)(C:\Users\93468\AppData\Roaming\Typora\typora-user-images\双向链表.png)]

源码:
  1. 成员属性

    	transient int size = 0;//链表长度
    
        /**
         * Pointer to first node.
         */
        transient Node<E> first;//链表头
    
        /**
         * Pointer to last node.
         */
        transient Node<E> last;//链表尾
    
  2. 构造器

    无参的话,真的就啥都没做,初始化完,first和last就是默认的null

    有参的话,是一个Collection类型参数,会把调无参构造,并将该集合里的所有元素都添加到LinkedList里面

    public LinkedList() {
        }
    
    
    public LinkedList(Collection<? extends E> c) {
           	this();
            addAll(c);
        }
    
  3. add():添加

    进来直接调用了LinkList的linkLast方法,

    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++;
        }
    
  4. remove():删除

    无参默认删除第一个节点,并返回该节点的element

    public E remove() {
            return removeFirst();
        }
        
    public E removeFirst() {
            final Node<E> f = first;
            if (f == null)
                throw new NoSuchElementException();
            return unlinkFirst(f);
        }
    
    private E unlinkFirst(Node<E> f) {
            // assert f == first && f != null;
            final E element = f.item;
            final Node<E> next = f.next;
            f.item = null;
            f.next = null; // help GC
            first = next;
            if (next == null)
                last = null;
            else
                next.prev = null;
            size--;
            modCount++;
            return element;
        }
    

    其他的比较多,不一一列举了,不过总体就是数据结构里面的双向链表的各种操作。

  5. ArrayList与LinkedList的比较

    底层结构增删的速率改查的效率
    ArrayList可变数组较低、数组扩容较高
    LinkedList双向链表较高、通过链表追加较低
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值