ArrayList源码阅读笔记
ArrayList
ArrayList继承自AbstractList抽象类,实现了RandomAccess, Cloneable, java.io.Serializable接口,其中RandomAccess是一个标志接口,代表可以支持快速随机访问,实现该接口的类使用for循环比使用迭代器要快,LinkedList并未实现该接口,它用迭代器进行遍历要比ArrayList用迭代器要快。可以用instanceof确定某obj是否实现RandomAccess。Cloneable:标志接口,表示可被克隆;java.io.Serializable可序列化标志接口。(克隆和序列化还能继续研究 。。。)
ArrayList是动态的、长度可变的,但底层由长度不可变的数组实现,默认数组大小为10,可以用ArrayList(int lenth)
初始化数组长度,也可以使用ensureCapacity(int minCapacity)
来预估数据数量而提前扩容(用此方法扩容时ArrayList不能为空数组)。
在进行扩容时多次使用Arrays.copyOf(obj [],newObj [])
方法,扩容大小由内部方法newCapacity(int minCapacity)
确定:
/**
* Returns a capacity at least as large as the given minimum capacity.返回至少与给定最小容量相同的容量
* Returns the current capacity increased by 50% if that suffices.如果满足,则返回当前容量增加50%
* Will not return a capacity greater than MAX_ARRAY_SIZE unless
* the given minimum capacity is greater than MAX_ARRAY_SIZE.
*除非给定的最小容量大于MAX_ARRAY_SIZE,否则不会返回大于MAX_ARRAY_SIZE的容量。
* @param minCapacity the desired minimum capacity
* @throws OutOfMemoryError if minCapacity is less than zero
*/
private int newCapacity(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;//原长度
int newCapacity = oldCapacity + (oldCapacity >> 1);//原长度1.5倍
if (newCapacity - minCapacity <= 0) {//如果给定长度大于1.5倍
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
return Math.max(DEFAULT_CAPACITY, minCapacity);//为空则返回给定和默认中大的
if (minCapacity < 0) // overflow不能给负数
throw new OutOfMemoryError();
return minCapacity;//否则就返回给定值
}
return (newCapacity - MAX_ARRAY_SIZE <= 0)
? newCapacity
: hugeCapacity(minCapacity);//这里,MAX_ARRAY_SIZE为Integer.MAX_VALUE-8,因为部分虚拟机会存储head code(头部信息?),所以直接给Integer.MAX_VALUE会报错:数组大小超出VM限制。但它还是会把这8个位置给你233333
}
说完扩容,说缩容,正常情况下开辟过的容量并不会减少,不使用了会赋null(比如clear()方法,以及内部的protected void removeRange()
),但这样会造成浪费,因此可以使用trimToSize()方法把其中的数组大小修改为元素数量(trim:修剪)。
其中add、remove方法使用System.arraycopy(Object src, int srcPos,Object dest, int destPos,int length)
来创建新的数组,从而表现出长度可变的特性。//这么做代表数组中间不会有null值,但是数组尾部未使用的会有null值。
removeAll(c),可以删除和c相同的元素,也就是求与c的差集;
retainAll(c),可以保留和c相同的元素,也就是求与c的交集。这两个方法都调用了期内部方法`batchRemove方法:
boolean batchRemove(Collection<?> c, boolean complement,
final int from, final int end) {
Objects.requireNonNull(c);//c中不能有null
final Object[] es = elementData;//获取原数组
int r;//声明遍历标志位
// Optimize for initial run of survivors
//优化幸存者的初始运行,也就是处理需要保留的元素
for (r = from;; r++) {
if (r == end)//removeAll与retainAll方法调用时传参from为0,end为数组大小size,这里判断是否需要执行删除操作
return false;//false代表没有元素删除
if (c.contains(es[r]) != complement)
break;//代表需要删除元素
}
int w = r++;//声明保留标志位,初始化为第一个要删除的元素,同时r+1继续遍历
try {
for (Object e; r < end; r++)
if (c.contains(e = es[r]) == complement)
es[w++] = e;//这里执行的不是删除,而是将后面需要保留的元素覆盖掉第一个需要删除的元素,相当于把需要保留的元素向前移动了
} catch (Throwable ex) {
// Preserve behavioral compatibility with AbstractCollection,
// even if c.contains() throws.
//保留与AbstractCollection的行为兼容性,即使c.contains()抛出也是如此。
System.arraycopy(es, r, es, w, end - r);
w += end - r;
throw ex;
} finally {
modCount += end - w;//修改(删除)的次数
shiftTailOverGap(es, w, end);//拷贝需要保留的元素,同时将后面移动过后的元素赋null
}
return true;//代表修改(删除)了元素
}
该方法还是比较精妙的。
至于迭代器了,恕笔者学识尚浅,就不发表拙见了//待更新。。。
疑点:其中两个私有的io方法,这俩玩意有什么用?私有不说,光见它声明没见它调用啊//待更新。。。
/**
* Saves the state of the {@code ArrayList} instance to a stream
* (that is, serializes it).
*
* @param s the stream
* @throws java.io.IOException if an I/O error occurs
* @serialData The length of the array backing the {@code ArrayList}
* instance is emitted (int), followed by all of its elements
* (each an {@code Object}) in the proper order.
*/
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException {
// Write out element count, and any hidden stuff
int expectedModCount = modCount;
s.defaultWriteObject();
// Write out size as capacity for behavioral compatibility with clone()
s.writeInt(size);
// Write out all elements in the proper order.
for (int i=0; i<size; i++) {
s.writeObject(elementData[i]);
}
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
}
/**
* Reconstitutes the {@code ArrayList} instance from a stream (that is,
* deserializes it).
* @param s the stream
* @throws ClassNotFoundException if the class of a serialized object
* could not be found
* @throws java.io.IOException if an I/O error occurs
*/
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
// Read in size, and any hidden stuff
s.defaultReadObject();
// Read in capacity
s.readInt(); // ignored
if (size > 0) {
// like clone(), allocate array based upon size not capacity
SharedSecrets.getJavaObjectInputStreamAccess().checkArray(s, Object[].class, size);
Object[] elements = new Object[size];
// Read in all elements in the proper order.
for (int i = 0; i < size; i++) {
elements[i] = s.readObject();
}
elementData = elements;
} else if (size == 0) {
elementData = EMPTY_ELEMENTDATA;
} else {
throw new java.io.InvalidObjectException("Invalid size: " + size);
}
}
ArrayList源码阅读笔记的更多相关文章
- ArrayList源码阅读笔记(1.8)
目录 ArrayList类的注解阅读 ArrayList类的定义 属性的定义 ArrayList构造器 核心方法 普通方法 迭代器(iterator&ListIterator)实现 最后声明 ...
- ArrayList源码阅读笔记(基于JDk1.8)
关键常量: private static final int DEFAULT_CAPACITY = 10; 当没有其他参数影响数组大小时的默认数组大小 private static final Obj ...
- jdk源码阅读笔记-LinkedHashMap
Map是Java collection framework 中重要的组成部分,特别是HashMap是在我们在日常的开发的过程中使用的最多的一个集合.但是遗憾的是,存放在HashMap中元素都是无序的, ...
- CopyOnWriteArrayList源码阅读笔记
简介 ArrayList是开发中使用比较多的集合,它不是线程安全的,CopyOnWriteArrayList就是线程安全版本的ArrayList.CopyOnWriteArrayList同样是通过数组 ...
- Mina源码阅读笔记(四)—Mina的连接IoConnector2
接着Mina源码阅读笔记(四)-Mina的连接IoConnector1,,我们继续: AbstractIoAcceptor: 001 package org.apache.mina.core.rewr ...
- HashMap源码阅读笔记
HashMap源码阅读笔记 本文在此博客的内容上进行了部分修改,旨在加深笔者对HashMap的理解,暂不讨论红黑树相关逻辑 概述 HashMap作为经常使用到的类,大多时候都是只知道大概原理,比如 ...
- java8 ArrayList源码阅读
转载自 java8 ArrayList源码阅读 本文基于jdk1.8 JavaCollection库中有三类:List,Queue,Set 其中List,有三个子实现类:ArrayList,Vecto ...
- CI框架源码阅读笔记5 基准测试 BenchMark.php
上一篇博客(CI框架源码阅读笔记4 引导文件CodeIgniter.php)中,我们已经看到:CI中核心流程的核心功能都是由不同的组件来完成的.这些组件类似于一个一个单独的模块,不同的模块完成不同的功 ...
- CI框架源码阅读笔记4 引导文件CodeIgniter.php
到了这里,终于进入CI框架的核心了.既然是“引导”文件,那么就是对用户的请求.参数等做相应的导向,让用户请求和数据流按照正确的线路各就各位.例如,用户的请求url: http://you.host.c ...
随机推荐
- kubernetes集群全栈监控报警方案kube-prometheus
参考文档 http://www.servicemesher.com/blog/prometheus-operator-manual/ https://github.com/coreos/prometh ...
- 变相降价的iPhone,能挽救苹果在中国的命运吗?
人无千日好,花无百样红.当年iPhone的横空出世不仅开辟了智能手机时代,还间接导致了诺基亚.黑莓等手机品牌的没落.十余年来,苹果凭借iPhone活得风光无限,并成为全球首个市值超万亿美元的公司.但进 ...
- python 字符串实例:检查并判断密码字符串的安全强度
检查并判断密码字符串的安全强度 import string def check(pwd): #密码必须至少包含六个字符 if not isinstance(pwd,str) or len(pwd)&l ...
- Git设置ssh密钥
前提条件是,公司的gitlab,运维没有关闭ssh的权限获取,或者叫运维开通那个ssh权限,生成的公钥要给运维那边一个!这样设置是可以成功 一.创建ssh key 1.在客户端查看有没有密钥 cd ~ ...
- java csv文件写入
List<String> list_code = null; 方案1 控制字符集: BufferedWriter bw=new BufferedWriter(new OutputStrea ...
- leeetcode1171 Remove Zero Sum Consecutive Nodes from Linked List
""" Given the head of a linked list, we repeatedly delete consecutive sequences of no ...
- spring boot 接口service有多个实现类
接口.java public interface DeService { } 接口实现类1.java @Service("ud")public class DeServiceImp ...
- NAND厂商哭晕:减产也阻止不了跌价
导读 NAND闪存价格已经连跌了6个季度,这让上游NAND厂商三星.东芝.美光等损失惨重,纷纷削减NAND产能.在群联台北电脑展上,群联公司董事长潘建成也预测NAND闪存价格已经跌破了成本,未来跌幅会 ...
- 云时代架构阅读笔记五——Java内存模型详解(一)
什么是Java内存模型 Java虚拟机规范中试图定义一种Java内存模型(Java Memory Model,JMM)来屏蔽掉各种硬件和操作系统的访问差异,以实现让Java程序在各种平台下都能达到一致 ...
- bugku - pwn wp
一. PWN1 题目:nc 114.116.54.89 10001 1. 直接kali里面跑nc 2.ls看看有啥 3.明显有一个flag cat查看一下 搞定 二 . PWN2 题目:给了nc 1 ...