ArraList源码分析
来源:互联网 发布:季后赛数据排名 编辑:程序博客网 时间:2024/06/05 21:53
一、对于ArrayList需要掌握的七点内容
- ArrayList的创建:即构造器
- 往ArrayList中添加对象:即add(E)方法
- 获取ArrayList中的单个对象:即get(int index)方法
- 删除ArrayList中的对象:即remove(E)方法
- 遍历ArrayList中的对象:即iterator,在实际中更常用的是增强型的for循环去做遍历
- 判断对象是否存在于ArrayList中:contain(E)
- ArrayList中对象的排序:主要取决于所采取的排序算法(以后讲)
二、源码分析
2.1、ArrayList的创建(常见的两种方式)
List<String> strList = new ArrayList<String>(); List<String> strList2 = new ArrayList<String>(2);//是创建list的时候[private transient Object[] elementData;//elementData存储ArrayList内的元素 private int size;//size表示它包含的元素的数量,就是存进在list里面的数据 // 构造方法,initialCapacity来初始化elementData数组的大小 public ArrayList(int initialCapacity) { super(); //即父类protected AbstractList() {} if (initialCapacity < 0) throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); this.elementData = new Object[initialCapacity];//在这初始化数组的大小 } /** * . 无参构造函数 */ public ArrayList() { this(10); }]注意:
- transient关键字的作用:在采用Java默认的序列化机制的时候,被该关键字修饰的属性不会被序列化。
- ArrayList类实现了java.io.Serializable接口,即采用了Java默认的序列化机制
- 上面的elementData属性采用了transient来修饰,表明其不使用Java默认的序列化机制来实例化,但是该属性是ArrayList的底层数据结构,在网络传输中一定需要将其序列化,之后使用的时候还需要反序列化,那不采用Java默认的序列化机制,那采用什么呢?直接翻到源码的最下边有两个方法,发现ArrayList自己实现了序列化和反序列化的方法
在我们执行new ArrayList<String>()时,会调用上边的无参构造器,创造一个容量为10的对象数组。
在我们执行new ArrayList<String>(2)时,会调用上边的public ArrayList(int initialCapacity),创造一个容量为2的对象数组。
注意:
- 上边有参构造器的super()方法是ArrayList父类AbstractList的构造方法,这个构造方法如下,是一个空构造方法:
protected AbstractList() { }
- 在实际使用中,如果我们能对所需的ArrayList的大小进行判断,有两个好处:
- 节省内存空间(eg.我们只需要放置两个元素到数组,new ArrayList<String>(2))
- 避免数组扩容(下边会讲)引起的效率下降(eg.我们只需要放置大约37个元素到数组,new ArrayList<String>(40))
2.2.1、add(E)
strList2.add("hello");
public class Add { /** * 向elementData中添加元素 */ public boolean add(E e) { ensureCapacity(size + 1);//确保对象数组elementData有足够的容量,可以将新加入的元素e加进去 elementData[size++] = e;//加入新元素e,size加1 return true; } /** * 确保数组的容量足够存放新加入的元素,若不够,要扩容 */ public void ensureCapacity(int minCapacity) { modCount++; int oldCapacity = elementData.length;//获取数组大小(即数组的容量) //当数组满了,又有新元素加入的时候,执行扩容逻辑 if (minCapacity > oldCapacity) { Object oldData[] = elementData; int newCapacity = (oldCapacity * 3) / 2 + 1;//新容量为旧容量的1.5倍+1 if (newCapacity < minCapacity)//如果扩容后的新容量还是没有传入的所需的最小容量大或等于(主要发生在addAll(Collection<? extends E> c)中) newCapacity = minCapacity;//新容量设为最小容量 elementData = Arrays.copyOf(elementData, newCapacity);//复制新容量 } }
在上述代码的扩容结束后,调用了Arrays.copyOf(elementData, newCapacity)方法,这个方法中:对于我们这里而言,先创建了一个新的容量为newCapacity的对象数组,然后使用System.arraycopy()方法将旧的对象数组复制到新的对象数组中去了。
注意:
- modCount变量用于在遍历集合(iterator())时,检测是否发生了add、remove操作。
2.2.2、addAll(Collection<? extends E> c)
使用方式:
List<String> strList = new ArrayList<String>(); strList.add("jigang"); strList.add("nana"); strList.add("nana2"); List<String> strList2 = new ArrayList<String>(2); strList2.addAll(strList);
源代码:
/** * 将c全部加入elementData */ public boolean addAll(Collection<? extends E> c) { Object[] a = c.toArray();//将c集合转化为对象数组a int numNew = a.length;//获取a对象数组的容量 ensureCapacity(size + numNew);//确保对象数组elementData有足够的容量,可以将新加入的a对象数组加进去 System.arraycopy(a, 0, elementData, size, numNew);//将对象数组a拷贝到elementData中去 size += numNew;//重新设置elementData中已加入的元素的个数 return numNew != 0;//若加入的是空集合则返回false }
注意:
- 从上述代码可以看出,若加入的c是空集合,则返回false
- ensureCapacity(size + numNew);这个方法在上边讲
- System.arraycopy()方法定义如下:
public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length);
将数组src从下标为srcPos开始拷贝,一直拷贝length个元素到dest数组中,在dest数组中从destPos开始加入先的srcPos数组元素。
阅读全文
0 0
- ArraList源码分析
- ArraList的用法
- ArraList,LinkList,List,Vector的区别
- java对list,ArraList进行排序
- 源码分析
- 源码分析
- 源码分析
- 源码分析
- 源码分析
- 源码分析
- 源码分析
- 源码分析
- 源码分析:SparseArray分析
- 源码- Spark Broadcast源码分析
- Android源码/框架源码分析
- 【Android应用源码分析】HandlerThread 源码分析
- 【Android应用源码分析】IntentService 源码分析
- java源码分析01-Object源码分析
- Android开发工具
- GKRandomDistribution
- 2017.05.14-1 SpringBoot简单登录注册-登录
- ZooKeeper原理及使用
- 在 PHP 中养成 7 个面向对象的好习惯
- ArraList源码分析
- SSH实现的增删改查实例
- JAVA八大排序算法
- Linux 目录
- 取两个集合中的相同元素
- spring cloud架构
- codeforce868c
- spring声明式事务 同一类内方法调用事务失效
- Effective Java阅读笔记(一)——第二章 创建和销毁对象