IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> ArrayList的源码分析 -> 正文阅读

[系统运维]ArrayList的源码分析

集合体系

优点

  • 降低编程难度
  • 提高程序性能
  • 提高API间的互操作性
  • 降低学习难度
  • 降低设计和实现相关API的难度
  • 增加程序的重用性

Collection

容器主要包括 Collection 和 Map 两种,Collection 存储着对象的集合,而 Map 存储着键值对(两个对象)的映射表。

List接口

常用实现类

Arraylist类

用数组实现

LinkedList类

链表类 实现了Queue 和 List接口

Vector

和ArrayList差不多 子类有一个 stack

Set接口 继承 Collection接口

TreeSet

基于红黑树实现,支持有序性操作,例如根据一个范围查找元素的操作。但是查找效率不如 HashSet,HashSet 查找的时间复杂度为 O(1),TreeSet 则为 O(logN)。

HashSet

基于哈希表实现,支持快速查找,但不支持有序性操作。并且失去了元素的插入顺序信息,也就是说使用 Iterator 遍历 HashSet 得到的结果是不确定的。

LinkedHashSet

具有 HashSet 的查找效率,且内部使用双向链表维护元素的插入顺序。

Queue 继承 Collection接口

LinkList

可以用它来实现双向队列。

PriorityQueue

基于堆结构实现,可以用它来实现优先队列。

Map

TreeMap

有顺序。

HashMap

键值对应

LinkedHashMap

使用双向链表来维护元素的顺序,顺序为插入顺序。

源码剖析

List接口下的ArrayList

ArrayList 顺序容器,元素存放的顺序与放进去的顺序相同,允许放入null值底层是一个数组。 该类 没有实现线程的同步,是线程不安全的。

由于底层 是一个 Object 数组 可以放进任何元素 这里使用了泛型来表示任意元素的类型

我们知道 数组 在 查找元素方面的效率 是常数级别的。

ArrayList 的构造方法

ArrayList (int initialCapacity)

ArrayList()

ArrayList(Collection<? extends E> c)

//源码  初始化容量
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 ArrayList() {
 this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
 //赋给一个空的数组。
  }
//集合作为参数的构造方法
public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();
    //传进来的集合转为数组
        if ((size = elementData.length) != 0) {
            // c.toArray might (incorrectly) not return Object[] (see 6260652)
            if (elementData.getClass() != Object[].class)
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
            // replace with empty array.
            //传进来的集合没有值的话  初始化空数组
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }

对于两个常量数组 为什么这么规范

可以看下面这个博客

EMPTY_ELEMENTDATA和DEFAULTCAPACITY_EMPTY_ELEMENTDATA两个空数组的区别_闻赤松之清尘,愿承风乎遗则的博客-CSDN博客

自动扩容的机制

数组进行扩容时,会将老数组中的元素重新拷贝一份到新的数组中,每次数组容量的增长大约是其原容量的1.5倍。

源码如下

//字段
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

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);
        // 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) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }
  

每次扩容1.5倍 这种代价 是很高的 容量不够 的话 一直递增给数组扩容 会花费较长的时间

我们可以使用ensureCapacity(int)方法进行手动扩容 我们知道 要存的元素个数 我们直接手动扩容 这样会减少不少的时间

add,addAll()方法

//末尾添加
  public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }
//指定位置添加元素
  public void add(int index, E element) {
        rangeCheckForAdd(index);
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        System.arraycopy(elementData, index, elementData, index + 1,
                         size - index);
        elementData[index] = element;
        size++;
    }
//这里没加if  没看懂
//数组大了就是扩容 —> 涉及到 数组的复制
//然后 添加元素 -> 涉及到数组的移动 所以有着n的时间复杂度

addAll() 分析

public boolean addAll(Collection<? extends E> c) {
        Object[] a = c.toArray();//转数组
        int numNew = a.length;//长度
        ensureCapacityInternal(size + numNew);  // Increments modCount
        System.arraycopy(a, 0, elementData, size, numNew);//原生拷贝  不会有新的地址
        size += numNew;
        return numNew != 0;
    }
//指定位置的拷贝
public boolean addAll(int index, Collection<? extends E> c) {
        rangeCheckForAdd(index);

        Object[] a = c.toArray();
        int numNew = a.length;
        ensureCapacityInternal(size + numNew);  // Increments modCount

        int numMoved = size - index;
        if (numMoved > 0)
            System.arraycopy(elementData, index, elementData, index + numNew,numMoved);                            

原生拷贝方法解析

public static void arraycopy(Object[] src, int srcPos, Object[] dest, int destPos, int length)

src:源数组;

srcPos:源数组要复制的起始位置;

dest:目的数组;

destPos:目的数组放置的起始位置;

length:复制的长度.

set(), get()

地城数组 通过下标改值即可

trimToSize()

功能 :将底层数组的容量调整为当前列表保存的实际元素的大小的功能

//源码
public void trimToSize() {
        modCount++;//防止并发修改的操作。
        if (size < elementData.length) {
            elementData = (size == 0)
              ? EMPTY_ELEMENTDATA
              : Arrays.copyOf(elementData, size);
        }
    }

indexOf(),lastIndexOf()方法

功能:获取索引

//底层是使用equals方法判断对象是否相等的
 public int indexOf(Object o) {
        if (o == null) {
            for (int i = 0; i < size; i++)
                if (elementData[i]==null)
                    return i;
        } else {
            for (int i = 0; i < size; i++)
                if (o.equals(elementData[i]))
                    return i;
        }
        return -1;
    }
//返回最后一次出现的索引
   public int lastIndexOf(Object o) {
        if (o == null) {
            for (int i = size-1; i >= 0; i--)
                if (elementData[i]==null)
                    return i;
        } else {
            for (int i = size-1; i >= 0; i--)
                if (o.equals(elementData[i]))
                    return i;
        }
        return -1;
    }
  
  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2021-11-11 13:06:47  更:2021-11-11 13:08:06 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/15 23:53:05-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码