想必大家除了String类,那么ArrayList类,用的也不少吧,那么今天我们去底层看看这个类的面目
作者博客:书生个人博客
##一.了解ArrayList类,那么我们先从构造函数开始说:
从上图我们可以知道
如果你是
ArrayList<String> b=new ArrayList<>();
那么会调用无参的构造函数,而无参的会调用有参的,并给的大小是10,那么出现了个问题,我们平常用的话,感觉ArrayList是没有大小的啊,可以一直add,不像我们普通的数组那样,是固定大小的啊。
对啊,那如果平常你的数组不够用,再添加的话,会出现数组下标越界异常,那么这时我们是不是可以在创建一个新的数组(比之前的大),然后复制过来(arrayCopy()函数,下面有说)。那么ArrayList底层是不是默默的帮我们做了呢 接着看
我们接着看
ensureCapacityInternal(size + 1);
size:是一个成员变量,初始化为0
从上面我们可以看到,当minCapacity>数组的大小时,会执行grow()函数,而这个函数就是扩容数组用的
(什么是minCapacity??
minCapacity与size有关,很简单,一开始size为0,然后把进来的e放在数组中,再size+1,每次add,我们先要执行 ensureCapacityInternal(size + 1);,主要是判断数组是否满了,然后对其进行扩容,那他是怎么扩容的呢,是不是也是用数组复制方法呢?接着看
grow函数
这儿有一段代码:int newCapacity = oldCapacity + (oldCapacity >> 1),>>是移位运算符,相当于int newCapacity = oldCapacity + (oldCapacity/2),但性能会好一些。,也就是新的数组是原来数组的1.5倍,并给原来的数组,这样,那数组是不是无形的变大1.5倍了啊.
我们再看一下复制函数的代码:
它还调用了一个
接着我们再看arraycopy()方法
好奇怪,这个方法只有定义,却没有实现,方法用了一个native来修饰。native的方法,是由其它语言来实现的,一般是(C或C++),所以这儿没有实现代码。这是一个数组拷贝方法,大家还在写for循环拷贝数组吗?以后多用这个方法吧,简单又方便还能获得得更好的性能。
我们接着看一下size()的源码:
一开始,size为0,而数组大小就10,所以我们这直接返回时size,代表的时这个数组目前有多少个元素,而不是数组的大小
##二.Vector与ArrayList的区别呢?
Vector源码跟ArrayList差不多,就是
1.Vector 只要是关键性的操作,方法前面都加了synchronized关键字,来保证线程的安全性。当执行synchronized修饰的方法前,系统会对该方法加一把锁,方法执行完成后释放锁,加锁和释放锁的这个过程,在系统中是有开销的,因此,在单线程的环境中,Vector效率要差很多。(多线程环境不允许用ArrayList,需要做处理)。
###2.至于底层数组的扩容区别,
和ArrayList和Vector一样,同样的类似关系的类还有HashMap和HashTable,StringBuilder和StringBuffer,后者是前者线程安全版本的实现。希望以后大家在面试过程中,能说出个因为所以,而不是一味的去背面试题,唯有理解,无需再背。