集合类——List接口常用实现类

集合

为什么要使用集合?

弥补数组不足之处:

  1. 长度必须使用前指定,且不能更改

  2. 储存的的数据类型必须统一

  3. 数据增删比较麻烦

集合的优点:

  1. 动态储存任意长度任意类型数据,包括null

  2. 提供一系列操作数据对象的方法add,remove,set,get等操作更简洁

框架体系

java集合主要分为两大类 单列集合,双列集合

所谓单列集合就是数据存储为单个对象,例如Colletion接口的实现类,而双列集合则是以键值对的形式存储,例如Map接口的实现类

Collection接口

Collection接口继承了Iterable接口,实现了可迭代,所以Collection接口所有实现子类均可以使用迭代器遍历

Collection接口

Collection接口常用方法

List接口实现子类对象均可使用

boolean add•(E e)   
 单个元素添加。
     
 boolean addAll•(Collection<? extends E> c)  
 将指定集合中的所有元素添加到此集合中。
     
 void clear()    
 从此集合中删除所有元素。
     
 boolean contains•(Object o) 
 如果此collection包含指定的元素,则返回 true 。
     
 boolean containsAll•(Collection<?> c)   
 如果此集合包含指定集合中的所有元素,则返回 true 。
     
 boolean equals•(Object o)   
 将指定对象与此集合进行比较以获得相等性。
     
 Iterator<E> iterator()  
 返回此集合中元素的迭代器。
     
 boolean remove•(Object o)   
 从此集合中移除指定元素的单个实例(如果存在)。
     
 boolean removeAll•(Collection<?> c) 
 删除此集合的所有元素,这些元素也包含在指定的集合中。
     
 int size()  
 返回此集合中的元素数。
     
 Object[] toArray()  
 返回包含此集合中所有元素的数组。

List接口常用方法

void add•(int index, E element) 
 将指定元素插入此列表中的指定位置(可选操作)。
     
 boolean add•(E e)   
 将指定的元素追加到此列表的末尾(可选操作)。
     
 boolean addAll•(int index, Collection<? extends E> c)   
 将指定集合中的所有元素插入到指定位置的此列表中(可选操作)。
     
 boolean addAll•(Collection<? extends E> c)  
 将指定集合中的所有元素按指定集合的迭代器(可选操作)返回的顺序追加到此列表的末尾。
     
 void clear()    
 从此列表中删除所有元素(可选操作)。
     
 boolean contains•(Object o) 
 如果此列表包含指定的元素,则返回 true 。
     
 boolean containsAll•(Collection<?> c)   
 如果此列表包含指定集合的所有元素,则返回 true 。
     
 boolean equals•(Object o)   
 将指定对象与此列表进行比较以获得相等性。
     
 E get•(int index)   
 返回此列表中指定位置的元素。
     
 int indexOf•(Object o)  
 返回此列表中第一次出现的指定元素的索引,如果此列表不包含该元素,则返回-1。
     
 boolean isEmpty()   
 如果此列表不包含任何元素,则返回 true 。
     
 Iterator<E> iterator()  
 以适当的顺序返回此列表中元素的迭代器。
     
 int lastIndexOf•(Object o)  
 返回此列表中指定元素最后一次出现的索引,如果此列表不包含该元素,则返回-1。
     
 E remove•(int index)    
 删除此列表中指定位置的元素(可选操作)。
     
 boolean remove•(Object o)   
 从该列表中删除指定元素的第一个匹配项(如果存在)(可选操作)。
     
 boolean removeAll•(Collection<?> c) 
 从此列表中删除指定集合中包含的所有元素(可选操作)。
     
 E set•(int index, E element)    
 用指定的元素替换此列表中指定位置的元素(可选操作)。
     
 int size()  
 返回此列表中的元素数。
     
 default void sort•(Comparator<? super E> c) 
 根据指定的Comparator引发的顺序对此列表进行排序。
     
 List<E> subList•(int fromIndex, int toIndex)    
 返回指定的 fromIndex (包含)和 toIndex (不包括)之间的此列表部分的视图。
     
 Object[]    toArray()   
 以适当的顺序(从第一个元素到最后一个元素)返回包含此列表中所有元素的数组。
     
 <T> T[] toArray•(T[] a) 
 以适当的顺序返回包含此列表中所有元素的数组(从第一个元素到最后一个元素); 返回数组的运行时类型是指定数组的运行时类型。

List接口常见实现子类及特点

List接口继承了Collection接口

  1. List集合实现类元素有序(添加取出顺序一致),且可重复

  2. 支持索引

ArrayList

底层维护了一个Object数组,线程不安全。增删效率较Vector较高

可以添加null,且多个

创建对象时选择构造器

ArrayList() 
 构造一个初始容量为0的空列表。
 ArrayList(int initialCapacity)  
 构造具有指定初始容量的空列表。

扩容方式

  • 无参构造初始化

    1. 构造一个初始容量为0的空列表。

      private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
       ​
       //无参构造
       public ArrayList() {
               this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;//{}
       }
    2. 添加元素时需要扩容

      public boolean add(E e) {
               // 当前元素数量量加1,检查容量是否够用,选择是否扩容
               ensureCapacityInternal(size + 1);  // Increments modCount!!
               elementData[size++] = e;
               return true;
           }
       ​
           transient Object[] elementData; // non-private to simplify nested class access
           private void ensureCapacityInternal(int minCapacity) {//minCapcity 需要的最小容量,即    size+1
               ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
           }
       ​
           private static final int DEFAULT_CAPACITY = 10;
           private static int calculateCapacity(Object[] elementData, int minCapacity) {
               //如果当前数组是无参构造时初始化的空数组
               if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
                   //返回 10 和所需容量的最大值
                   return Math.max(DEFAULT_CAPACITY, minCapacity);
               }
               return minCapacity;
           }
       ​
           private void ensureExplicitCapacity(int minCapacity) {
               //参数modCount记录了 某个List改变大小的次数,如果modCount改变的不符合预期,那么就会抛出异常。    
               modCount++;
             
               // 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 + (oldCapacity >> 1);//当前容量1.5倍,如果是空还是0
               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);//扩容底层实际上还是数组扩容
           }
  • 有参构造初始化

    有参构造初始化给定初始容量,添加元素容量不足时在当前容量基础上1.5倍扩容

Vector

语法和ArrayList相同,除了同步情况是线程安全的,及无参构造初始化默认容量10,后按当前容量2倍扩容,也可在构造方法中指定扩容增量,如果指定大小则扩容直接为指定大小两倍

构造方法
Vector()构造一个空向量,使其内部数据数组的大小为 10 ,标准容量增量为零。
Vector(int initialCapacity)构造具有指定初始容量并且其容量增量等于零的空向量。
Vector(int initialCapacity, int capacityIncrement)构造具有指定的初始容量和容量增量的空向量。
//扩容核心代码 
 newCapacity = oldCapacity + ((capacityIncrement > 0) ? capacityIncrement : oldCapacity);//capacityIncrement = 0

LinkedList

语法和ArrayList相同,底层使用双向链表,每个节点由数据item,前驱prev,后继next组成

实现了双向链表和双端队列的特点可以添加任意元素(可重复),包括 null

线程不安全,没有实现同步

构造器

构造器描述
LinkedList()构造一个空列表。
LinkedList(Collection<? extends E> c)按照集合的迭代器返回的顺序构造一个包含指定集合元素的列表。

底层源码

//初始化空列表
     public LinkedList() {
     }
     
     //链表属性
     transient int size = 0; // 节点数量
     transient Node<E> first;//链表第一个节点
     transient Node<E> last;//链表最后一个节点
 ​
     //添加元素
     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;//last指向新节点,充当最后一个节点
         if (l == null)//如果未添加前最后一个节点是空,即是空列表
             first = newNode;//新节点为第一个节点
         else
             l.next = newNode;//否则把新节点放到最后
         size++;//数据个数
         modCount++;//修改次数
     }
 ​
 ​
     //删除,以按照索引删除为例
     public E remove(int index) {
         checkElementIndex(index);
         return unlink(node(index));
     }
 ​
     private void checkElementIndex(int index) {
         if (!isElementIndex(index))
             throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
     }
 ​
     private boolean isElementIndex(int index) {//判断索引是否符合要求
         return index >= 0 && index < size;
     }
 ​
     Node<E> node(int index) {
         // 折半处理两种情况
 ​
         if (index < (size >> 1)) {//左半边
             Node<E> x = first;
             for (int i = 0; i < index; i++)
                 x = x.next;
             return x;
         } else {
             Node<E> x = last;
             for (int i = size - 1; i > index; i--)
                 x = x.prev;
             return x;
         }
     }
 ​
     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;
     }

ArratList,Vector,LinkedList区别

底层实现优缺点线程安全扩容方式(无参构造初始化)
ArrayList可变数组增删效率低查找效率高否(相比于Vector增删效率高)0->10->1.5倍扩容
Vector可变数组增删效率低查找效率高10->2倍扩容
LinkedList链表增删效率高查找效率低/

效率

查询速度上看: Vector ≈ ArrayList > LinkedList 增删改速度上看:Vector < ArrayList < LinkedList

遍历方式

  1. for循环,使用size()方法获取长度,get()方法获取元素

  2. 增强for循环

  3. 迭代器(因为Colletion接口继承了Iterable接口)

    迭代器使用需要Iterator()方法初始化迭代器,该方法在Collection的父接口Iterable中定义了

     Iterator<T> iterator()  
     返回 T类型的元素的迭代器。
         
     Iterator iterator = List1.iterator();
     //每次往后迭代时需要判断是否到最后一个元素了,使用hasnext()方法
     while (iterator.hasNext()) {
        Object next =  l.next();
        System.out.println(next);
     }

    下面应该是Collection接口的子接口Set接口,不过Set接口常用实现子类TreeSet和HashSet在了解完Map接口后再了解更友好,所以放在Map接口后面讲!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

富士的雪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值