动态数组
List接口是Collection接口的一个子类。
List接口是一个储存有序的、可重复的数据,它是一个动态的数组。我们想要实现它有三种方法。
以及它们三个都能实现动态数组区别在哪里呢?
ArrayList | LinkedList | Vector |
---|---|---|
出现版本:jdk1.2 | 出现版本:jdk1.2 | 出现版本:jdk1.0,所以它是古老实现类,list集合是jdk1.2出现的 |
线程不安全,效率高 | 线程不安全,效率高 | 线程安全,效率低 |
底层采用Object[] elementData数组储存 | 底层使用双向链表储存 | 底层采用Object[] elementData数组储存 |
查询更快,插入删除不方便(因为是数组) | 插入删除更方便,查询不方便(因为是链表) |
ArrayList底层原理:
1.在jdk7的情况下
ArrayList list=new ArrayList(); //底层创建了长度为10的object[]数组elementData
list.add(123);//elementData[0]=new Integer(123);
…
list.add(11);//如果本次操作导致底层elementData数组容量不够,则扩容。
默认情况下,扩容(调用grow方法)为原来的1.5倍(就是原数组长度+>>1,右移一位),同时需要将原有数组中的数据赋值到新的数组中。如果扩容完了发现还不够,就拿该容量充当新长度。如果扩容的长度接近默认的最大值,就取最大值。
数组扩容是采用Arrays.copyOf复制的。删除是采用System.arraycopy复制的
结论:建议开发中采用带参的构造器:ArrayList list=new ArrayList(int capacity)
2.在jdk8的变化:
ArrayList list=new ArrayList(); //底层object[]数组elementData初始化为{ },并没有创建长度。
list.add(123); //第一次调用add时,底层才创建长度为10的数组,并将数据添加到数组elementData
…
后续的添加和扩容与jdk7无异。
3.小结:jdk7的ArrayList的对象创建类似于单例的饿汉式,而jdk8创建类似于单例的懒汉式,延迟了数组的创建,节省内容
补充:
ArrayList 的序列化问题?
因为长度问题,可能会有空的地方,所以ArrayList的writeObject方法就会显式的为每个实际的数组元素进行序列化,只序列化有用的元素。
ArrayList实现了Cloneable接口,支持返回浅拷贝,
ArrayList和Vector的区别?
答:(1)同步性:Vector是同步的,线程安全的;ArrayList是不同步的,线程不安全的
(2)数据增长:ArrayList默认增长为原来的1.5倍,Vector默认增长为原来的2倍
LinkedList和ArrayList的区别?
答:LinkedList类似于双向链表,ArrayList类似于数组,所以ArrayList查找数据方便,LinkedList增删数据方便
常用方法:
- 增:add(Object obj)
- 删:remove(int index)/ remove(Object obj) !!!同时含有的时候,采用remove(int index)
- 改:set(int index)
- 查:get(int index)
- 插:add(int index,Object obj)
- 长度:size()
- 遍历:①Iterator迭代器 ②增强for循环 ③普通的循环
public class test {
public static void main(String[] args) {
List list1=new ArrayList();
List list2=new LinkedList();
List list3=new Vector();
//增
list1.add(3);
list1.add("4");
list1.add(1);
list1.add(2);
System.out.println(list1); //[3, 4, 1, 2]
//删
//当含有2时,优先删除的是索引2处的,所以删除的是1
list1.remove(2);
System.out.println(list1); //[3, 4, 2]
list1.remove("4");
System.out.println(list1); //[3, 2]
//改
list1.set(0,6); //将第0位转换成6
System.out.println(list1); //[6, 2]
//查
System.out.println(list1.get(0)); //6
//插
list1.add(1,"5");
System.out.println(list1); //[6, 5, 2]
//长度
System.out.println(list1.size()); //3
//遍历
//方法一:迭代器的方式
Iterator iterator=list1.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next()); //6 5 2
}
//方法二:增强for循环
for (Object o:list1) {
System.out.println(o); //6 5 2
}
//方法三:普通循环
for (int i=0;i<list1.size();i++){
System.out.println(list1.get(i)); //6 5 2
}
}
}