ArrayList是List接口的可变数组的实现。实现了所有可选列表操作,并允许包括 null 在内的所有元素。除了实现 List 接口外,此类还提供一些方法来操作内部用来存储列表的数组的大小,下面将从ArrayList的属性及相关方法进行概述
属性
private transient Object[] elementData;
为实际数据的存储对象,可以看出ArrayList实际存储数据对象为对象数组,所以ArrayList实际为对对象数组操作的封装,从这里我们也可以看出ArrayList没有容量限制。
private int size;
当前对象数组中已经存在元素个数size小于等对象数组的大小,
创建
ArrayList API提供了三种构造方法,常用的两种如下
public ArrayList() { //调用ArrayList(int initialCapacity) this(10); } public ArrayList(int initialCapacity) { super(); if (initialCapacity < 0) throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); //创建存储数据对象 this.elementData = new Object[initialCapacity]; }
对于默认的new ArrayList()来说,可以分析得到创建默认大小的object数组,数组的初始化大小为10,默认创建时size未赋值,因是类变量size将初始为0;
增加元素
public boolean add(E e) { //校验数组容量 ensureCapacity(size + 1); // Increments modCount!! //将数据对象插入到数组的size末端 elementData[size++] = e; return true; } //插入指定位置的元素 public void add(int index, E element) { //索引>size或索引小于0直接抛出异常 if (index > size || index < 0) throw new IndexOutOfBoundsException( "Index: "+index+", Size: "+size); ensureCapacity(size+1); // Increments modCount!! //将index后面的数据后移一位 System.arraycopy(elementData, index, elementData, index + 1, size - index); //将数据插入到指定index位置 elementData[index] = element; //size加一 size++; } public void ensureCapacity(int minCapacity) { modCount++; //原有数组容量大小 int oldCapacity = elementData.length; //插入的索引位置大于数组容量,增大数组容量 if (minCapacity > oldCapacity) { Object oldData[] = elementData; //数组容量增大,按照原数组容量大小0.5增加 int newCapacity = (oldCapacity * 3)/2 + 1; //增大的容量如果还是小于插入的索引位置,将索引直接赋值给新的数组容量 if (newCapacity < minCapacity) newCapacity = minCapacity; //将数组按照新的数组容量进行扩容 elementData = Arrays.copyOf(elementData, newCapacity); } }
增加是先校验底层的对象数组是否能再添加元素,如果没法添加,先将对象数组进行扩容【要进行一次数组拷贝】,扩容因子为0.5。再进行插入。如果能添加元素,直接将数据插入到size对应的索引位置。如果插入到指定位置将会涉及到数组元素的后移【进行一次数组拷贝】,相关请看add(int index, E element)注解。同时我们也可以发现对于NULL值和重复值也未进行处理。
读取元素
public E get(int index) { RangeCheck(index);//校验index大小 return (E) elementData[index];//获取index位置的数据 } private void RangeCheck(int index) { if (index >= size) throw new IndexOutOfBoundsException( "Index: "+index+", Size: "+size); }
读取最简单就是从对象数组中将对应索引位置的数据读取出来。读取的索引小于size。
删除
public E remove(int index) { RangeCheck(index);//检查index大小 modCount++; E oldValue = (E) elementData[index];//标记删除位置的值 int numMoved = size - index - 1;//计算删除索引到size剩入数据 if (numMoved > 0)//如果剩入数据大于0,则将index后的数据进行前移。 System.arraycopy(elementData, index+1, elementData, index, numMoved); elementData[--size] = null; //将size大小-1,并将elementData的原来索引位置为size-1的数据清空。 return oldValue; }
删除涉及到数组的前移,前移的数据范围为删除索引的值+1到size-1的元素。注意我们发现删除并未和写入时一样进行对象数组的大小的自动收缩【即存储容量未发生变化】。
按照元素值进行删除
public boolean remove(Object o) { if (o == null) { //遍历数组,发现第一个null值所在地 for (int index = 0; index < size; index++) if (elementData[index] == null) { fastRemove(index); return true; } } else { //遍历数组,发现第一个元素值所在地 for (int index = 0; index < size; index++) if (o.equals(elementData[index])) { //进行删除 fastRemove(index); return true; } } return false; } private void fastRemove(int index) { modCount++; //计算要前移动的数据个数 int numMoved = size - index - 1; if (numMoved > 0) //进行数组拷贝将index后数据前移一位 System.arraycopy(elementData, index+1, elementData, index, numMoved); //size-1并将size-1索引位置的元素清空, elementData[--size] = null; // Let gc do its work }
按照元素值进行删除,会遍历数组对象,遍历元素个数为删除元素的索引index+1,且只会删除该元素值出现第一个。并且在删除是,对象数组会进行拷贝,拷贝元素个数为size-index-1。
压缩对象数组存储容量
public void trimToSize() { modCount++; int oldCapacity = elementData.length; //当前数组的大小小于当前数组存储大小进行压缩 if (size < oldCapacity) { elementData = Arrays.copyOf(elementData, size); } }
压缩的时候是以size为标准,将对象数组的大小压缩为size一样大小。
清空
public void clear() { modCount++; // 将数组中数据清空 for (int i = 0; i < size; i++) elementData[i] = null; //将size大小设置为0 size = 0; }
清空主要进行两件事情:(1):将相关的数据元素设置为NULL值。(2):将size设置为0
其他的不做介绍了,ArrayList主要是针对对象数组的操作,主要围绕size展开。
总结:
(1):ArrayList的实际存储对象为一个数组对象。没有容量大小,可以无限增加【扩展因子为0.5】,只受JVM内存大小限制。
(2):ArrayList中可以包含重复的元素,并可以存储NULL值。
(3):ArrayList的所有方法都是非线程安全的。
(4):ArrayList的索引访问和元素更新方面有着非常优秀的性能,因为不需要花费精力做范围检查,所以从ArrayList的末端添加元素,删除元素也有着非常优秀的性能,除非ArrayList的存储容量不足而需要扩展内部数组的长度【扩展的时候需要数组拷贝】。插入和删除数据需要一个数组的拷贝,需要拷贝的元素数量是ArrayList的元素长度(size-1)减去索引号,对插入来讲,插入元素到ArrayList的第一个元素位置的性能最差,插入到最后一个位子的性能最好,数组拷贝所需的时间会根据元素的数量增加而显著增加。
(5):ArrayList查找指定位置的数据时间为O(1),插入到指定位置的数据时间为O(size-index-1)。
(6):ArrayList插入大量的元素,提前指定ArrayList的大小,防止在插入过程ArrayList进行扩容。
(7):ArrayList按照元素值进行删除时,会遍历数组对象,并且会进行数组拷贝,时间为O(index+1)+O(size-index-1),可以计算总共花费O(size),遍历的对象+拷贝的对对象就等于元素个数。
(8):ArrayList删除时,不会调整原有的数组存储容量的大小即在数组存储容量扩容的后删除所用扩容数据后也不会调整整个数组容量大小,手工调用trimToSize进行调整。
相关推荐
ava基础 基础知识 面向对象基础 Java基本数据类型 string和包装类 final关键字特性 Java类和包 抽象类和接口 代码块和代码执行顺序 Java自动拆箱装箱里隐藏的秘密 ...Java集合详解8:Java集合类细节精讲 JavaWeb
Java集合类总结 Java集合详解:一文读懂ArrayList,Vector与Stack使用方法和实现原理 Java集合详解:Queue和LinkedList Java集合详解:迭代器,快速失败机制与比较器 Java集合详解:HashMap和HashTable Java集合详解...
Java集合框架:这部分问题关注ArrayList、LinkedList、HashMap、HashSet等集合类的特性和使用。例如,比较ArrayList和LinkedList的优缺点;解释HashMap的工作原理和如何处理哈希冲突;讨论如何选择合适的集合类来...
# Java面试题深入解析:在互联网公司面试程序员需要留意的六个问题 在互联网公司中,Java...在面试中,面试官可能会问及Java集合中的ArrayList和LinkedList的区别是什么?HashMap和TreeMap的区别是什么等等。 ## 4.
│ Java面试题10.ArrayList LinkedList.mp4 │ Java面试题11.HashMap和HashTable的区别.mp4 │ Java面试题12.实现一个拷贝文件的类使用字节流还是字符串.mp4 │ Java面试题13.线程的实现方式 怎么启动线程怎么区分...
这个Java文件包含了10个示例代码,旨在深入理解Java的核心概念和用法。每个示例都展示了不同的方面,涵盖了面向对象编程、继承和多态、接口和实现、异常处理、集合框架、文件操作、多线程、输入输出、Lambda表达式和...
- 字符串与集合:深入String类和集合框架,如ArrayList、HashMap。 - 异常处理:介绍try-catch和自定义异常。 五、I/O与文件操作 - I/O流:讲解输入输出流的基本概念。 - 文件操作:指导文件的读写和操作。 六、...
集合框架:熟悉Java集合框架中的List、Set、Map等接口及其实现类,如ArrayList、HashSet、HashMap等。 泛型:理解泛型的概念及其在Java中的应用,如泛型类和泛型方法。 并发编程:了解Java中的线程、同步、锁等机制...
1.4.1 类(Class):Java世界中一类物体 14 1.4.2 方法(Method):物体的功能 15 1.4.3 main()方法:所有Java程序执行的起点 15 .1.5 名词解释 16 1.5.1 JDK和Java平台 16 1.5.2 Java编译器(Java Compiler)...
1.4.1 类(Class):Java世界中一类物体 14 1.4.2 方法(Method):物体的功能 15 1.4.3 main()方法:所有Java程序执行的起点 15 .1.5 名词解释 16 1.5.1 JDK和Java平台 16 1.5.2 Java编译器(Java Compiler)...
7.4.2 ArrayList和Vector实现类 264 7.4.3 固定长度的List 266 7.5 Queue接口 266 7.5.1 LinkedList实现类 266 7.5.2 PriorityQueue实现类 269 7.6 Map 270 7.6.1 HashMap和Hashtable实现类 271 7.6.2 ...
13.1.2 泛型与jdk 5.0中的集合类 13.2 使用泛型 13.2.1 创建支持泛型的类 13.2.2 泛型的自动解包装与自动包装的功能 13.2.4 限制泛型中类型参数的范围 小结 第14章 ajax技术与web应用性能优化 14.1 了解ajax 14.2 ...
高级java笔试题 interview 2017届春招秋招公司的面试题目 #阿里内推(Android开发) ##笔试 ####选择题: 快速排序 二叉树遍历 UML类图 ...7.java集合类,哪些线程安全,哪些线程不安全 8.线程安全
在Java当中,如果有一个类专门用来存放其它类的对象,这个类就叫做容器,或者就叫做集合,集合就是将若干性质相同或相近的类对象组合在一起而形成的一个整体之所以需要容器:1、数组的长度难以扩充2、数组中数据的...
这个工具类目前主要有25种正规表达式(有些不常用,但那时才仔细深入的研究了一下正规,写上瘾了,就当时能想到的都写了): 1.匹配图象; 2 匹配email地址; 3 匹配匹配并提取url ; 4 匹配并提取http ; 5.匹配日期 6...
需要程序员经常刷题吗simple-java-zh-CN Simple Java 是 Java 常见问题的集合。中文翻译 ##1。 字符串和数组字符串...深入理解Arrays.sort(T[], Comparator < ? super T > c) 常见排序,Collections、Arrays、Tre
java面试笔试资料包括JAVA基础核心知识点深度学习Spring面试题等资料合集: JAVA核心知识点整理-282页 Java与哈希算法.docx Java中Lambda表达式的使用.docx JAVA多线程之线程间的通信方式.docx Java注解详解.docx ...
remove方法对LinkedList类的使用3.3.5 关于ListIterator接口3.4 ArrayList类的实现3.4.1 基本类3.4.2 迭代器、Java嵌套类和内部类3.5 LinkedList类的实现3.6 栈ADT3.6.1 栈模型3.6.2 栈的实现3.6.3 应用3.7 队列...
Java 知识点,继续完善中。 多数是一些 Java 基础知识、底层原理、算法详解。也有上层应用设计,其中不乏一些大厂面试真题。 如果对你有帮助请点下 Star,有疑问欢迎提 ,有好的想法请提 。 常用集合 ArrayList/...