-
modcount 和 java的 Fail-Fast 机制有关 即为在可能发生错误的情况下提前抛出。
-
transient Object[] elementData; // non-private to simplify nested class access
这里的 non-private to simplify nested class access 翻译过来就是 非私有化以简化嵌套类访问 但是我们明明知道内部类明明可以透 明的访问内部类的所有成员,那么何谈简化呢?
查看反编译字节码便可一探究竟:
虚拟机不知道类的分组情况,会在类中提供非public方法以供内部类访问私有成员。内部类在访问外部类私有变量的同时,编译器会为外部类添加一个非公有方法,内部类通过持有外部类的引用,调用此方法,访问私有变量。
所以如果声明是非私有的,那么就可以简化编译器添加非公有方法的这个操作i,提高效率。这里的简化指的就是这个意思。
-
private static final Object[] EMPTY_ELEMENTDATA = {}; /** * Shared empty array instance used for default sized empty instances. We * distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when * first element is added. */ private static final Object[] DEFAULTCAPCITY_EMPTY_ELEMENTDATA= {};
关于EMPTY_ELEMENTDATA与DEFAULTCAPCITY_EMPTY_ELEMENTDATA的区别,其实中间的官方注释也解释了就是:
我们将其(DEFAULTCAPCITY_EMPTY_ELEMENTDATA)与EMPTY_ELEMENTDATA数据区分开来,以了解添加第一个元素时要膨胀多少。
这句话什么意思呢,我们看一下下面的源码就知道了:
Mylist是我对ArrayList的仿写 是一样的:
//无参构造构造直接赋值DEFAULTCAPCITY_EMPTY_ELEMENTDATA
public Mylist(){
this.element=DEFAULTCAPCITY_EMPTY_ELEMENTDATA;
}
// 只有 initialCapactitty == 0 的时候才会赋值 EMPTY_ELEMENTDATA
public Mylist(int initialCapactity){
if(initialCapactity > 0){
this.element= new Object[initialCapactity];
}else if(initialCapactity == 0){
this.element=EMPTY_ELEMENTDATA;
}else{
throw new IllegalArgumentException("Illegal Capacity: "+initialCapactity);
}
}
// 如果都第一次调用 add() 赋值的不同 将会带来下面函数的不同
// 如果是 DEFAULTCAPCITY_EMPTY_ELEMENTDATA 则可以扩容到 10
// 如果是 EMPTY_ELEMENTDATA 则只会 增加到 1
private static int calculateCapacity(Object[] element, int minCapacity){
//如果是空的 直接给10个空间 避免重复的grow;
if(element == DEFAULTCAPCITY_EMPTY_ELEMENTDATA){
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
4. 聊一聊ArrayList 的 动态扩容机制
public boolean add(E e){
ensureCapacityInternal(size + 1);
element[size++] = e;
return true;
}
ArrayLIst的add()方法是如何保持空间足够的呢? 我们看到源码中一个关键函数 便是 ensureCapacityInternal 了
让我来看看ensureCapacityInternal的调用过程
private static int calculateCapacity(Object[] element, int minCapacity){
//如果是空的 直接给10个空间 避免重复的grow;
if(element == DEFAULTCAPCITY_EMPTY_ELEMENTDATA){
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
private void ensureCapacityInternal(int minCapacity){
ensureExplicitCapacity(calculateCapacity(element, minCapacity));
}
private void ensureExplicitCapacity(int minCapacity){
modCount++;
// overflow-conscious code
if(minCapacity - element.length >0)
grow(minCapacity); //空间不够 扩容
}
// 最大数组大小 防止数组过大超过VM的限制
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
/**
* 数组增长函数
* @param minCapacity 需要的最小容量
*/
private void grow(int minCapacity){
// overflow-conscious code
int oldCapacity = element.length;
int newCapacity = oldCapacity +(oldCapacity >> 1); //右移缩小一倍 懂得都懂 哈哈哈 还有一件事(1.5倍)
if(newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if(newCapacity - MAX_ARRAY_SIZE > 0){
newCapacity = hugeCapacity(minCapacity);
}
}
private static int hugeCapacity(int minCapacity){
if(minCapacity < 0) //overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
下面是函数的调用流程
核心就是 每次空间不够 就扩大1.5倍 在于 需要的 最小容量进行比较 如果还是不够 直接等于最小容量 如果最小容量超出了数组最大上限制, 在调用hugeCapacity 扩大到 Integer.MAX_VALUE 这是最大了。
//爱jdk 也爱jk
//To Be A Romantic Programmer
2021/4/26