您的位置:首页 > 编程语言 > Java开发

Java知识:ArrayList类详解

2017-09-14 17:18 393 查看

1、ArrayList的本质是什么?

ArrayList本质是顺序表!


2、 什么是顺序表?

顺序表是在计算机内存中以数组的形式保存的线性表,是指用一组地址连续的存储单元依次存储数据元素的线性结构。只要确定了起始位置,表中任一元素的地址都通过下列公式得到:LOC(ai)=LOC(a1)+(i-1)*L  1≤i≤n 其中,L是元素占用存储单元的长度。



简单点说就是:以数组的形式保存的线性表(属于线性表中的一种)

3、ArrayList这个顺序表是如何实现的呢,证据呢?

ArrayList是通过数组实现的。
ArrayList构造函数如下:


一下代码摘抄自JDK源码,我只摘抄了需要用到的部分。

private transient Object[] elementData;//声明了一个object类型的数组

public ArrayList(int initialCapacity) {
super();
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
this.elementData = new Object[initialCapacity];//创建了一个initialCapacity容量的数组
}

/**
* Constructs an empty list with an initial capacity of ten.
*/
public ArrayList() {
this(10);
}


在构造函数中有一句话
this.elementData = new Object[initialCapacity];//创建了一个initialCapacity容量的数组


4、ArrayList初始容量是多少呢?

根据构造函数如果我们自定义了容量:ArrayList<String> al=new ArrayList<String>(20);那么容量就是20
如果我们没有自定义容量:ArrayList<String> al=new ArrayList<String>();那么容量就是10


5、ArrayList扩容扩多少呢?

现在我们看看add操作


public boolean add(E e) {
ensureCapacityInternal(size + 1);  // Increments modCount!!
elementData[size++] = e;
return true;
}


add操作的第一步就是执行ensureCapacityInternal方法。

private void ensureCapacityInternal(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}


modCount++;这个一会儿会讲到

if (minCapacity - elementData.length > 0)

grow(minCapacity);//如果容量小了就执行grow(minCapacity)函数,看来grow(minCapacity)是扩容函数的庐山真面目啊

private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);//扩容50%
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);
}


newCapacity = oldCapacity + oldCapacity / 2;

就是说每次当发现当前数组长度不足时,每次增加的步长是【0.5倍的当前长度】。

if (newCapacity - minCapacity < 0)

newCapacity = minCapacity;

比方说你有个10容量的数组,现在要通过addAll()方法增加10个元素,那么minCapacity就是20,newCapacity就是15,15小于20那么newCacacity就变成了20.也就是说此次扩容了100%。

if (newCapacity - MAX_ARRAY_SIZE > 0)

newCapacity = hugeCapacity(minCapacity);

如果你的newCapacity比MAX_ARRAY_SIZE(Integer.MAX_VALUE - 8)还要大的话就要看看 hugeCapacity(int 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;
}


根据hugeCapacity(int minCapacity) 方法,newCapacity= Integer.MAX_VALUE

这次扩容的比例应该小于等于50%

网上有人说他每次扩容50%也是不准确的。

6、在ArrayList中我们经常看到modCount,这个变量有什么用呢?

这位大神给出了很好的解答:

http://blog.csdn.net/qq_24235325/article/details/52450331

这其实Fail-Fast机制快速失败机制,这个机制以后再发博客吧。

7、protected transient int modCount = 0;中的transient关键字有啥用呢?

transient 修饰的变量不会序列化,关于序列化的知识以后再详细说明吧。

8、ArrayList是基于动态数组实现的?

Java中的数组都是静态数组(数组大小不可变)。

那ArrayList是基于动态数组实现的是不正确的吗?

ArrayList实现动态数组本质的创建新的数组,只是看起来原来的数组动态增长了!

这句话的正确与否取决于你对动态数组的理解和认识,你认为之前有个数组,之后创建一个新的可以算作“动态”那这句话是正确的。

如果你认为创建了一个新的,原来的是”静态“的,那么这句话是不正确的。

这个问题没有必要较真。

9、ArrayList为什么是不同步的?

看看jdk里ArrayList的add方法是如何写的



问题就出在size++这边,主要分为两个步骤:

1)将add的元素放到size位置

2)将size加1


  假设size=5.若线程A在5位置存放了值valueA,获得size=5,但还没来得及将size加1写入主存。此时线程B在也在5位置存放了值valueB,也获得size=5,而后A、B分别将size加1后写入主存,size=6,即两个线程执行两次add()后size只加了1。

总结:

1、ArrayList适合查找,不适合频繁的增删。

2、ArrayList不同步

3、如果可以确定ArrayList所需容量最好直接定义。

参考资料:

http://blog.csdn.net/li_ning_/article/details/52089861

http://www.cnblogs.com/dick159/p/6531004.html

http://www.cnblogs.com/shamo89/p/6672104.html

http://blog.csdn.net/qq_24235325/article/details/52450331
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java arraylist