List连环问
List连环问
List?
- List是一个接口,常见的实现类有ArrayList和LinkedList
ArrayList和LinkedList的区别?
- ArrayList的底层数据结构是数组,支持下标访问,查询数据快。默认初始值大小为10,容量不足时会进行扩容
- 而LinkedList的底层数据结构是链表,将元素添加到链表的末尾,无需扩容
ArrayList的扩容?
public boolean add(E e) {
ensureCapacityInternal(size + 1); //扩容
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
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);
}
- 在grow方法里面进行扩容,将数组容量扩大为原来的1.5倍。
- 扩容之后,会调用Arrays.copyOf()方法对数组进行拷贝。
ArrayList和LinkedList分别适用于什么场景?
- 对于随机index访问的get和set方法,ArrayList的速度要优于LinkedList。因为ArrayList直接通过数组下标直接找到元素;LinkedList要移动指针遍历每个元素直到找到为止。
- 新增和删除元素,LinkedList的速度要优于ArrayList。因为ArrayList在新增和删除元素时,可能扩容和复制数组;而LinkedList的新增和删除操作只需要修改指针即可。
- 因此,ArrayList适用于查询多,增删少的场景。而LinkedList适用于查询少,增删多的场景
Set和List的区别?
-
List 以索引来存取元素,有序的,元素是允许重复的,可以插入多个null;Set 不能存放重复元素,无序的,只允许插入一个null。
-
List 底层实现有数组、链表两种方式;Set 基于 Map 实现,Set 里的元素值就是 Map的键值。
了解Vector吗?
- Vector是底层结构是数组,现在基本没有使用Vector了,因为操作Vector效率比较低。相对于ArrayList,它是线程安全的,在扩容的时候容量扩展为原来的2倍。
线程安全的List吗?
-
使用Collections.synchronizedList()方法返回一个线程安全的List。
-
使用CopyOnWriteArrayList。
CopyOnWriteArrayList的原理?
-
CopyOnWriteArrayList是一个线程安全的List,底层是通过复制数组的方式来实现的。
-
所谓的CopyOnWrite,就是写时复制。
-
当我们往容器添加元素时,不直接往容器添加,而是先将当前容器进行复制,复制出一个新的容器,然后往新的容器添加元素,添加完元素之后,再将原容器的引用指向新容器。这样做的好处就是可以对CopyOnWrite容器进行并发的读而不需要加锁,因为当前容器不会被修改。
public boolean add(E e) {
final ReentrantLock lock = this.lock;
lock.lock(); //add方法需要加锁
try {
Object[] elements = getArray();
int len = elements.length;
Object[] newElements = Arrays.copyOf(elements, len + 1); //复制新数组
newElements[len] = e;
setArray(newElements); //原容器的引用指向新容器
return true;
} finally {
lock.unlock();
}
}
CopyOnWriteArrayList有什么缺点吗?
-
内存占用问题。由于CopyOnWrite的写时复制机制,在进行写操作的时候,内存里会同时驻扎两个对象的内存。
-
CopyOnWrite容器不能保证数据的实时一致性,可能读取到旧数据。
怎么给List排序呢?
- 可以使用list自身的sort方法,或者使用Collections.sort(list)方法。
遍历 ArrayList 时移除一个元素?
- 如果使用foreach删除元素的话,会导致快速失败(fast-fail)问题,可以使用迭代器的 remove() 方法,避免fast-fail问题。
Iterator itr = list.iterator();
while(itr.hasNext()) {
if(itr.next().equals("dabin") {
itr.remove();
}
}