Java容器ArrayList原理解析

这篇文章主要介绍了Java容器ArrayList原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

List是collection接口的实现类

List:

特点:有序,可重复

它有两个常用的实现类:

一。ArrayList:

特点:以数组的形式进行存储,因此随机访问速度较快,所有它适用于查询。

缺点:不适用于插入和删除的操作 因为每次操作都需要移动数组中的元素。

根据源码我们能得出以下几点:

1.ArrayList 在初始化的时候如果我们没有指定长度的话,它会有一个默认长度10,

private static final int DEFAULT_CAPACITY = 10;

2.如果我们在增加新元素的时候超过了原来的容量,那么ArrayList是怎么做的呢?

(底层扩容机制:扩容为原来的1.5倍)

这就涉及到了ArrayList的扩容机制,既然ArrayList是以数组形式存储的,那么肯定就继承了数组的特点一旦声明不可更改,那么既然不可更改,那java是怎么解决这个问题的呢?

transient Object[] elementData;

开头声明的这个就是一个临时的可变的数组 为以后数组扩容做准备

public boolean add(E e) {
    ensureCapacityInternal(size + 1); // Increments modCount!!
    elementData[size++] = e;
    return true;
  }

上边代码的ensureCapacityInternal(size+1) 就是扩容的开始

我们点进去源码继续深入

private void ensureCapacityInternal(int minCapacity) {
    ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
  }

  private void ensureExplicitCapacity(int minCapacity) {
    modCount++;

    // overflow-conscious code
    if (minCapacity - elementData.length > 0)
      grow(minCapacity);
  }

看到这我们发现了 ensureCapacityInternal中调用了ensureExplicitCapacity我们继续深入

private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};//默认的空集合

private static final int DEFAULT_CAPACITY = 10;//默认10
private static int calculateCapacity(Object[] elementData, int minCapacity) {      //如果当前的elemenrData(当前的数据)是一个空的集合 ,获取下一步的扩容的容量
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
      return Math.max(DEFAULT_CAPACITY, minCapacity);
    }
    return minCapacity;
  }

然后我们回到上一层

private void ensureExplicitCapacity(int minCapacity) {
    modCount++; //每次修改集合次数 (AbstractList.class中的值)
// 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倍(1.8,1.7)(1.6是 1.5倍+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;
  }

看完以上代码 我们可以得出来如果不给初始值,默认值为10,扩容时候不是在原数组上做更改,而是copy了一个数组 按1.5倍增长

3.ArrayList是线程不安全的。如果要实现线程安全 可以使用 synchronized关键字 或者使用Collections.synchronizedList()方法 如下:

List<Object> objects = Collections.synchronizedList(new ArrayList<>());

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Java源码解析CopyOnWriteArrayList的讲解

    本文基于jdk1.8进行分析. ArrayList和HashMap是我们经常使用的集合,它们不是线程安全的.我们一般都知道HashMap的线程安全版本为ConcurrentHashMap,那么ArrayList有没有类似的线程安全的版本呢?还真有,它就是CopyOnWriteArrayList. CopyOnWrite这个短语,还有一个专门的称谓COW. COW不仅仅是java实现集合框架时专用的机制,它在计算机中被广泛使用. 首先看一下什么是CopyOnWriteArrayList,它的类前面

  • Java中ArrayList在foreach里remove的问题详析

    前言 ArrayList就是传说中的动态数组,用MSDN中的说法,就是Array的复杂版本,它提供了如下一些好处: 动态的增加和减少元素 实现了ICollection和IList接口 灵活的设置数组的大小 都说ArrayList在用foreach循环的时候,不能add元素,也不能remove元素,可能会抛异常,那我们就来分析一下它具体的实现.我目前的环境是Java8. 有下面一段代码: public class TestForEachList extends BaseTests { @Test

  • java ArrayList.remove()的三种错误用法以及六种正确用法详解

    java集合中,list列表应该是我们最常使用的,它有两种常见的实现类:ArrayList和LinkedList.ArrayList底层是数组,查找比较方便:LinkedList底层是链表,更适合做新增和删除.但实际开发中,我们也会遇到使用ArrayList需要删除列表元素的时候.虽然ArrayList类已经提供了remove方法,不过其中有潜在的坑,下面将介绍remove方法的三种错误用法以及六种正确用法. 1.错误用法 1.1.for循环中使用remove(int index),列表从前往后

  • 详解Java中ArrayList类

    ArratList 类:存放同一数据类型容器(只能为引用数据类型,因实际其内部存放的是地址) 1.导入其所在包 import java.util.ArratList 2.创建对象 ArrayList<E> 对象名=new ArrayList<>(); E:泛型数据类型,指定对象名中存放指定类型的数据,不可省略,需为引用数据类型 3.使用 即对象名.方法(参数可能有可能无) 注意:当打印对象名时,非地址,而是一个如同python中列表一般,存放的是各个数据[元素1,元素2],若无数据

  • java中申请不定长度数组ArrayList的方法

    如下所示: import java.util.ArrayList; //java中申请不定长度数组 public class Test01 { public static void main(String[] args) { // TODO Auto-generated method stub ArrayList list=new ArrayList(); list.add("123"); list.add("5"); list.add("5")

  • Java中Array List与Linked List的实现分析

    一,前言 ​ 先来一张Collection集合图. 今天分享一些关于Collection集合中的List,讲真的集合这东西在网上真是老生常谈了.说实话连本人都觉得腻了(哈哈),但是话又说回来,整个集合体系对于我们实际开发来说是非常重要的,所以还是有必要系统总结下. 不过在此之前先说说两种数据结构,链表和红黑树. 1.1,链表 ​链表:linked list,由一系列结点node(链表中每一个元素称为结点)组成,结点可以在运行时动态生成.每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存

  • Java ArrayList的底层实现方法

    如下所示: package com.soto.collection; /** * 自己实现一个ArrayList,帮助我们更好地理解ArrayList的底层结构; * @author 王 * */ public class SxtArrayList { private Object[] elementData; private int size; public int size(){ return size; } public boolean isEmpty(){ return size ==

  • Java 集合系列(二)ArrayList详解

    ArrayList ArrayList 是通过一个数组来实现的,因此它是在连续的存储位置存放对象的引用,只不过它比 Array 更智能,能够根据集合长度进行自动扩容. 假设让我们来实现一个简单的能够自动扩容的数组,我们最容易想到的点就是: add()的时候需要判断当前数组size+1是否等于此时定义的数组大小: 若小于直接添加即可:否则,需要先扩容再进行添加. 实际上,ArrayList的内部实现原理也是这样子,我们可以来研究分析一下ArrayList的源码 add(E e) 源码分析 /**

  • Java容器ArrayList原理解析

    这篇文章主要介绍了Java容器ArrayList原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 List是collection接口的实现类 List: 特点:有序,可重复 它有两个常用的实现类: 一.ArrayList: 特点:以数组的形式进行存储,因此随机访问速度较快,所有它适用于查询. 缺点:不适用于插入和删除的操作 因为每次操作都需要移动数组中的元素. 根据源码我们能得出以下几点: 1.ArrayList 在初始化的时候如果我们没

  • JAVA容器集合全面解析(Collection和Map)

    目录 前言 一.Collection集合 1.1List集合 1.1.1ArrayList集合 1.1.2LinkedList集合 1.2Set集合 1.2.1HashSet集合 HashSet集合保证元素唯一性源码分析: 1.2.2TreeSet集合 比较器排序Comparator的使用: 二.Map集合 2.1Map集合的概述与特点 2.2Map集合的获取功能 2.3Map集合的遍历方式(方式一) 2.4Map集合的遍历方式(方式二) 2.5HashMap集合 前言 本次我将分享的是java

  • Java transient关键字原理解析

    这篇文章主要介绍了Java transient关键字原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 Java 中的 transient 关键字被用来表示变量将不被序列化处理.那么在理解 transient 关键字之前,我们先了解下什么是序列化. 什么是序列化 序列化是对象进行持久化处理,也就是说,将对象转化成一个字节流进行存储(比如存储为一个字节文件)或传输(通过网络传输字节).同时,我们也可以从字节中反序列化一个对象出来.这是Java

  • java char数据类型原理解析

    这篇文章主要介绍了java char数据类型原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 java中的 char 数据类型使用 Unicode 编码,占用两个字节内存. 因为Unicode 采用无符号编码,一共可以存储 0x0000 ~ 0xffff 共65536 个字符, 而 int 是有符号4个字节,刚好一半是2个字节,所以在 java 将 char 看作整数(0-65535),于是我做了一个测试: //unicode 无符号编码

  • Java多线程 ThreadLocal原理解析

    目录 1.什么是ThreadLocal变量 2.ThreadLocal实现原理 3.内存泄漏问题 4.使用场景 1)存储用户Session 2)解决线程安全的问题 3)使用ThreadLocal重新设计一个上下文设计模式 4)ThreadLocal注意事项 脏数据 内存泄漏 父子线程共享线程变量 1.什么是ThreadLocal变量 ThreadLoal 变量,线程局部变量,同一个 ThreadLocal 所包含的对象,在不同的 Thread 中有不同的副本. 这里有几点需要注意: 因为每个 T

  • Java原子操作CAS原理解析

    一.CAS(Compare And Set) Compare And Set(或Compare And Swap),CAS是解决多线程并行情况下使用锁造成性能损耗的一种机制,CAS操作包含三个操作数--内存位置(V).预期原值(A).新值(B).如果内存位置的值与预期原值相匹配,那么处理器会自动将该位置值更新为新值.否则,处理器不做任何操作.无论哪种情况,它都会在CAS指令之前返回该位置的值.CAS有效地说明了"我认为位置V应该包含值A:如果包含该值,则将B放到这个位置:否则,不要更改该位置,只

  • Java容器ArrayList知识点总结

    ArrayList 底层实现是数组,访问元素效率高 (查询快,插入.修改.删除元素慢) 与LinkedList相比,它效率高,但线程不安全. ArrayList数组是一个可变数组,可以存取包括null在内的所有元素 每个ArrayList实例都有一个容量,该容量是指用来存储列表元素的数组的大小 随着向ArrayList中不断增加元素,其容量自动增长 在添加大量元素前,应用程序也可以使用ensureCapacity操作来增加ArrayList实例的容量,这样可以减少递增式再分配的数量. 所以如果我

  • Java Number类原理实例解析

    这篇文章主要介绍了Java Number类原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 Number类 内置数据类型:byte.int.long.double等 包装类:Integer.Long.Byte.Double.Float.Short. ​ 这种由编译器特别支持的包装称为装箱,所以当内置数据类型被当作对象使用的时候,编译器会把内置类型装箱为包装类.相似的,编译器也可以把一个对象拆箱为内置类型.Number 类属于 java.l

  • Java并发CopyOnWrite容器原理解析

    这篇文章主要介绍了Java并发CopyOnWrite容器原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 Copy-On-Write简称COW,是一种用于程序设计中的优化策略.其基本思路是,从一开始大家都在共享同一个内容,当某个人想要修改这个内容的时候,才会真正把内容Copy出去形成一个新的内容然后再改,这是一种延时懒惰策略.从JDK1.5开始Java并发包里提供了两个使用CopyOnWrite机制实现的并发容器,它们是CopyOnWri

  • Java线程的并发工具类实现原理解析

    目录 一.fork/join 1. Fork-Join原理 2. 工作窃取 3. 代码实现 二.CountDownLatch 三.CyclicBarrier 四.Semaphore 五.Exchange 六.Callable.Future.FutureTask 在JDK的并发包里提供了几个非常有用的并发工具类.CountDownLatch.CyclicBarrier和Semaphore工具类提供了一种并发流程控制的手段,Exchanger工具类则提供了在线程间交换数据的一种手段.本章会配合一些应

随机推荐