1.java集合框架里面List常见基础面试题
说下Vector和ArrayList、LinkedList联系和区别?分别的使用场景
2.List的掌握情况(追问系列)
如果需要保证线程安全,ArrayList应该怎么做,用有几种方式
3.基于CopyOnWriteArrayList进行继续追问
如果回答到上面的点则继续问,了解CopyOnWriteArrayList吗?和 Collections.synchronizedList实现线程安全有什么区别, 使用场景是怎样的?
CopyOnWriteArrayList的设计思想是怎样的,有什么缺点?
补概念——Yong GC和Full GC
总结
以上转载自:https://www.icode9.com/content-1-891506.html
4.基于List进行继续二次追问,进阶扩容机制+源码剖析
说下ArrayList的扩容机制是怎样的
5.基于List进行继续追问,进阶连环炮,代码实战
设计一个简单的ArrayList【需要包含 构造函数(有参和无参)、add(obj)、 扩容机制】
设计一个简单的ArrayList【remove(index)、get(index) 、indexOf(o) ,set(int index,Object obj)】
import java.io.Serializable; public class MyArrayList implements Serializable { //使用这个字段,来判断当前集合类是否被并发修改,即迭代器并发修改的fail-fast机制 private transient int modCount = 0; //第一次扩容的容量 private static final int DEFAULT_CAPACITY = 10; //用于初始化空的list private static final Object[] EMPTY_ELEMENT_DATA = {}; //实际存储的元素 transient Object[] elementData; //实际list集合大小,从0开始 private int size; public MyArrayList() { this.elementData = EMPTY_ELEMENT_DATA; } public MyArrayList(int initialCapcity) { if (initialCapcity > 0) { this.elementData = new Object[initialCapcity]; } else if (initialCapcity == 0) { this.elementData = EMPTY_ELEMENT_DATA; } else { throw new IllegalArgumentException("参数异常"); } } public boolean add(Object e) { //判断容量 ensureCapacityInternal(size + 1); //使用下标赋值,尾部插入 elementData[size++] = e; return true; } /** * 计算容量+确保容量 * @param minCapacity 需要的容量 */ private void ensureCapacityInternal(int minCapacity) { //用于并发判断 modCount++; //如果是初次扩容,则使用默认的容量 if (elementData == EMPTY_ELEMENT_DATA) { minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); } //是否需要扩容,需要的最少容量大于现在数组的长度则要扩容 if (minCapacity - elementData.length > 0) { int oldCapacity = elementData.length; int newCapacity = oldCapacity + (oldCapacity >> 1); //如果新容量 < 最小容量, 则讲最新的容量赋值给新的容量 if (newCapacity - minCapacity < 0) { newCapacity = minCapacity; } //创建新数组 Object[] objects = new Object[newCapacity]; //将旧的数组复制到新的数组里面 System.arraycopy(elementData, 0, objects, 0, elementData.length); //修改引用 elementData = objects; } } /** * 通过下标获取对象 * @param index * @return */ public Object get(int index){ rangeCheck(index); return elementData[index]; } private void rangeCheck(int index) { if (index > size || size<0){ throw new IndexOutOfBoundsException("数组越界"); } } /** * 判断对象所在的位置 * @param o * @return */ public int indexOf(Object o){ if(o == null){ for (int i=0;i<size; i++){ if (elementData[i] == null){ return i; } } }else { for (int i=0;i<size;i++){ return i; } } return -1; } public Object set(int index,Object obj){ rangeCheck(index); Object oldValue = elementData[index]; elementData[index]= obj; return oldValue; } /** * 根据索引删除元素 * @param index * @return */ public Object remove(int index){ rangeCheck(index); //用于并发判断 modCount++; Object oldValue = elementData[index]; //计算要删除的位置后面有几个元素 int numMoved = size - index - 1; if (numMoved>0){ System.arraycopy(elementData,index+1,elementData,index,numMoved); } //将多出的位置设置为空,没有引用对象,垃圾收集器可以回收,如果不设置为空,将会保存一个引用,可能会造成内存泄漏 elementData[--size] = numMoved; return oldValue; } /** * 获取数组实际大小 * @return */ public int size(){ return this.size; } }
测试一下
import java.io.File; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; public class test { public static void main(String[] args) { MyArrayList list = new MyArrayList(); for (int i = 1;i<10;i++){ list.add(""+i); } list.remove(5); list.set(2,"qwqe"); for (int i = 0;i<list.size();i++){ System.out.println(list.get(i)); } } }
控制台输出
这里补充几个小知识点
Math.max()
console.log(Math.max(1, 3, 2)); // expected output: 3 console.log(Math.max(-1, -3, -2)); // expected output: -1 const array1 = [1, 3, 2]; console.log(Math.max(...array1)); // expected output: 3
输出结果
> 3
> -1
> 3
System.arraycopy
fail-fast
本文作者为DBC,转载请注明。