package Other;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Vector;
/**
* @author vincent
* @description 面试相关List
* @Date 2020-03-18 17:03
*/
public class LList {
public static void main(String[] args) {
/**
* ArrayList
*/
ArrayList<Object> arrayList = new ArrayList<>();
// 结构是数组 object[]
// 优点查找和访问速度更快 缺点新增删除慢线程不安全
// 延伸: 插入速度快但是查找速度慢的是linkedlist 线程安全的是vector
ArrayList<Object> objects = new ArrayList<>(10);
ArrayList<Object> objects2 = new ArrayList<>(10);
// 因为结构是数组,所以构造方法可以传入初始长度 默认是0
// Java经典bug 构造方法赋初始长度,只是构建了一个长度的数组,但是size还是0
// 如果此时set,会报越界错误 除非初始后就add够足够的长度
for (int i = 0; i < 10000; i++) {
objects.add(i);
objects2.add(i);
}
// objects.add(5,"5");
arrayList.add("");
// 空数组,只有第一次add操作才会赋值10的初始长度
// 数组扩容公式
// int newCapacity = oldCapacity + (oldCapacity >> 1); oldCapacity为当前数组长度 翻译:len+len/2
// 扩容方式和hashmap一样,都是新建一个数组 复制
// 10这个默认值,在Java里都是sun公司根据调研,得出的大概最有效率的一个初值
//新增删除效率问题
arrayList.add(null);// 普通新增不指定index则直接加在数组最后
// arrayList.add(5,null);
// 如果指定位置的话
// 看源代码可以看到,首先判断数组是否需要扩容,其次index+1后的所有数组进行copy,然后再把新增元素添加到index位置
// 如果数组长度够大,len-index-1的元素复制太多,效率可想而知
arrayList.remove(null); // 删除同理,先for循环对比得到index,len-index-1的元素向前复制,置len位置为null
// 新增删除就一点慢吗
// 答案是否定的,我们通过源码可以看到,arraylist主要是通过复制截取数组来实现的插入和删除,并不涉及移位,这里就考量到一个index,即操作的元素在数组中的位置
long startTime=System.nanoTime();
objects.remove(5000);
long endTime=System.nanoTime();
System.out.println("删除1000运行时间: "+(endTime - startTime)+"ms");
long endTime2=System.nanoTime();
objects2.remove(9000);
System.out.println("删除9000运行时间: "+(endTime2 - endTime)+"ms");
// 通过上面这段代码,我们能看出,index越靠近尾部,执行效率越低
//arraylist适合用来做队列吗
// 我们首先了解队列的原则应该是先入先出first in first out
// 即我们的remove要remove头,add要add尾,反过来也可以
// 我们知道arrayList的新增删除都需要复制移位,效率低,所以不适合
// 相反,数组是适合做队列的,经典的几个队列底层都是使用的定长环形队列
/**
* LinkedList
*/
LinkedList<Object> linkedList = new LinkedList<>();
// 结构链表
linkedList.add(null); // 插入因为只需要操作尾部的next即可,所以效率高
linkedList.add(1,null); // 先定位index,元素的next链接index的next,元素的pre链接index,index的next指向元素
linkedList.get(1); // 这里看源码可以看到,判断index和size/2,决定是在链表前半段查找,还是后半段查找
linkedList.indexOf(null);// indexof都是从头判断到尾
// 所有源码有modcount的都是failfast机制(快速失败),即遍历时,如果其他线程操作该元素导致该元素的modcount改变,则此次遍历会报错
/**
* 对比
*/
// arrayList因为底层结构是数组,数组是一片连续的空间,读取都很快,但是插入删除需要频繁的开辟新的数组复制
// linkedList因为底层结构是链表,链表没有扩容问题,有新数据就建一个node,改变前驱后驱即可,但是因为数据在内存中存储空间不连续,读取效率低
/**
* 线程安全的Vector
*/
Vector<Object> vector = new Vector<>();
// vector的源码其实和arrayList一模一样,只是每个方法上加了synchronized保证线程安全
}
}
面试相关-List总结
最新推荐文章于 2025-07-28 17:30:49 发布