想提升自己的java基础,但是不知道从何看起,因为自己很多东西只略知一二,很少去深究,基础薄弱。搜索如何学好Java基础,大多数都是提议查看源码,说实话我曾经几次想看源码的,但是还是害怕就放弃了。这一次,又鼓足勇气打开了java源码,这次我看的、学到的知识都会记录在此。我大概清楚java基础的几大重要模块:
- 集合
- 多线程
- I/O
- 网络
就先从集合开始看。
关于什么是集合,什么是ArrayList…这里就不再赘述了,网上太多了。只记录自己觉得不熟悉,看了几遍才看懂的东西。
ArrayList
transient Object[] elementData;
基于数组实现。
特点:
有序、可重复、查询较快、增删慢、不是线程安全。
fail-first
ArrayList采用的是fail-first。
fail-first 一种错误机制,当多个线程同时操作同一集合的内容就可能会发生。
原理:利用modCount,每次修改内容modCount++, 那么在迭代器的初始化过程中就会将这个值赋值给迭代器的expectedModCount, 判断modCount与expectedModCount的值是否相等,不相等就报 ConcurrentModificationException
一些方法的用途(以前没有接触的):
trimToSize()将当前列表大小最小化。当前的列表就是当前元素的个数。
foreach()结合 lambda表达式(后续了解)进行使用。
源码呈上
构造函数(这里就不呈上源码了)
- public ArrayList(Collection<? extends E> c) //复制其他Collection中的值
- public ArrayList(int initialCapacity) //初始化容量的大小
- public ArrayList() //使用初始容量的大小
扩容(重要)
这里就是数组与ArrayList的一个重要区别,后者可以自动扩容而前者不行
//初始容量的大小
private static final int DEFAULT_CAPACITY = 10;
//使用有参构造函数时,将ArrayList初始化为EMPTY_ELEMENTDATA,空数组指向它
private static final Object[] EMPTY_ELEMENTDATA = {};
//无参构造所创建的实例,将ArrayList 初始化为空
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
//这个是手动设置初始容量,在你清楚列表的大小时很有必要,因为自动扩容的开销非常大。
public void ensureCapacity(int minCapacity) {
int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
// any size if not default element table
? 0
// larger than default for default empty table. It's already
// supposed to be at default size.
: DEFAULT_CAPACITY;
if (minCapacity > minExpand) {
ensureExplicitCapacity(minCapacity);
}
}
public boolean add(E e) {
//看看前文的fist-fail
//判断是否需要扩容
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
//如果是空数组,就取最小要求的存储容量与默认容量的最大值
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
// 最小要求的存储容量若小于实际的存储容量,则扩容
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
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) {
//这里我没看懂,为什么最低要求的容量小于0,他就报异常,大佬可以在评论里告诉我下??
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
总结
我觉得最重要的是扩容这部分了。当是无参构造实例的ArrayList时,先是复制一个空数组给它,当执行添加时才会划分一个内存为10的空间。
ArrayList的储存范围是Integer.MAX_VALUE
若有错误,请指出,谢谢了。
继续,加油!!![2019/8/7]