2 LinkList实现List接口,可以存储null至其中。有两个指针,一个指向第一个元素,一个指向最后的元素。
/**
* Pointer to first node.
* Invariant: (first == null && last == null) ||
* (first.prev == null && first.item != null)
*/
transient Node<E> first;
/**
* Pointer to last node.
* Invariant: (first == null && last == null) ||
* (last.next == null && last.item != null)
*/
transient Node<E> last;
每一个元素的结构为一个指向前和指向后的指针。类似于数据结构中的双链表。
private static class Node<E> {
E item;
Node<E> next;
Node<E> prev;
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
头插法:
/**
* Links e as first element.
*/
private void linkFirst(E e) {
final Node<E> f = first;
final Node<E> newNode = new Node<>(null, e, f);
first = newNode;
if (f == null)
last = newNode;//插入之前是空,头尾指针均指向该节点
else
f.prev = newNode;//更新之前的头指针指向前的位置
size++;
modCount++;
}
尾插法:
/**
* Links e as last element.
*/
void linkLast(E e) {
final Node<E> l = last;
final Node<E> newNode = new Node<>(l, e, null);
last = newNode;
if (l == null)
first = newNode;//插入之前为空,头尾指针均指向它
else
l.next = newNode;//不要空,更新之前的尾指针的尾指向
size++;
modCount++;
}
自己实现的LinkedList
/**
* @Author: ShipTang
* @Description: LinkedList重写
* @Date: 2021/8/9 16:04
*/
public class LinkedListRewrite<E> {
/**
* 设置空节点,不用担心头节点和尾节点出现空指针
*/
private Node<E> emptyNode = new Node<>(null);
/**
* 头指针
*/
private Node<E> headNode = emptyNode;
/**
* 尾指针
*/
private Node<E> endNode = emptyNode;
/**
* 链表节点个数
*/
private Integer size = 0;
public void add(E e) {
Node<E> node = new Node<>(e);
this.endNode.nextNode = node;
node.preNode = this.endNode;
this.endNode = node;
size++;
}
public void add(int index, E e) {
if (index < 0 && index >= this.size) {
throw new ArrayIndexOutOfBoundsException("越过链表长度");
}
//获取被替换的节点
Node<E> indexNode = this.getNode(index);
Node<E> preNode = indexNode.preNode;
Node<E> newNode = new Node<>(e);
preNode.nextNode = newNode;
newNode.preNode = preNode;
newNode.nextNode = indexNode;
indexNode.preNode = newNode;
}
private Node<E> getNode(int index) {
if (index < (this.size >> 1)) {
//从头开始
Node<E> node = this.headNode.nextNode;
for (int i = 0; i < index; i++) {
node = node.nextNode;
}
return node;
} else {
//从尾开始
Node<E> node = this.endNode.preNode;
for (int i = size - 1; index < i; i--) {
node = node.preNode;
}
return node;
}
}
public E get(int index) {
if (index < 0 && index >= this.size) {
throw new ArrayIndexOutOfBoundsException("越过链表长度");
}
Node<E> node = this.getNode(index);
return node.e;
}
public E remove(int index) {
if (index < 0 && index >= this.size) {
throw new ArrayIndexOutOfBoundsException("越过链表长度");
}
Node<E> currNode = this.getNode(index);
Node<E> preNode = currNode.preNode;
Node<E> nextNode = currNode.nextNode;
preNode.nextNode = nextNode;
nextNode.preNode = preNode;
//断开
currNode.preNode = null;
currNode.nextNode = null;
return currNode.e;
}
public void printList() {
//从头到尾
Node<E> node1 = this.headNode.nextNode;
System.out.println("---------------从头到尾--------------");
while (node1 != this.endNode) {
System.out.print("->" + node1.e);
node1 = node1.nextNode;
}
//从尾到头
Node<E> node2 = this.endNode.preNode;
System.out.println();
System.out.println("---------------从尾到头--------------");
while (node2 != this.headNode) {
System.out.print("->" + node2.e);
node2 = node2.preNode;
}
}
private static class Node<E> {
private E e;
private Node<E> preNode;
private Node<E> nextNode;
Node(E e) {
this.e = e;
}
}
}
测试方法
@Test
public void add() {
LinkedListRewrite<Integer> linkedListRewrite = new LinkedListRewrite<>();
for (int i = 0; i < 16; i++) {
linkedListRewrite.add(i);
}
linkedListRewrite.printList();
}
@Test
public void add1() {
LinkedListRewrite<Integer> linkedListRewrite = new LinkedListRewrite<>();
for (int i = 0; i < 16; i++) {
linkedListRewrite.add(i);
}
linkedListRewrite.add(14, 1414);
linkedListRewrite.printList();
}
@Test
public void get() {
LinkedListRewrite<Integer> linkedListRewrite = new LinkedListRewrite<>();
for (int i = 0; i < 16; i++) {
linkedListRewrite.add(i);
}
for (int i = 0; i < 16; i++) {
System.out.println(linkedListRewrite.get(i));
}
}
@Test
public void remove() {
LinkedListRewrite<Integer> linkedListRewrite = new LinkedListRewrite<>();
for (int i = 0; i < 16; i++) {
linkedListRewrite.add(i);
}
for (int i = 0; i < 16; i++) {
System.out.println(linkedListRewrite.remove(0));
}
}
- ArrayList
- 扩容方法
//自增ArrayList空间大小
//参数minCapacity为增加的最小大小
private void grow(int minCapacity) {
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);//元素复制
}
每
次
扩
容
的
大
小
为
当
前
长
度
+
当
前
长
度
右
移
一
位
得
到
的
数
。
\color{#FF0000}{每次扩容的大小为当前长度+当前长度右移一位得到的数。}
每次扩容的大小为当前长度+当前长度右移一位得到的数。
n
e
w
A
r
r
a
y
L
i
s
t
数
组
时
大
小
为
一
个
空
数
组
,
执
行
添
加
任
务
的
时
候
,
初
始
化
大
小
为
10.
\color{#FF0000}{new ArrayList数组时大小为一个空数组,执行添加任务的时候,初始化大小为10.}
newArrayList数组时大小为一个空数组,执行添加任务的时候,初始化大小为10.
ArrayList的坑:
@Test
public void test02(){
String[] arrays = {"1", "2", "3"};
List<String> list = new ArrayList<>(Arrays.asList(arrays));
List<String> subList = list.subList(0, 1);
subList.set(0, "10");
System.out.println(JSON.toJSONString(list));
System.out.println(JSON.toJSONString(subList));
}
输出:
["10","2","3"]
["10"]
修改了是子集,结果影响到了父集合。解决方案为subList返回的结果集套一层ArrayList即可
@Test
public void test02(){
String[] arrays = {"1", "2", "3"};
List<String> list = new ArrayList<>(Arrays.asList(arrays));
List<String> subList = new ArrayList<>(list.subList(0, 1));
subList.set(0, "10");
System.out.println(JSON.toJSONString(list));
System.out.println(JSON.toJSONString(subList));
}
参考:https://mp.weixin.qq.com/s/1lHrVnMckr5NuNThVJkWMQ
在迭代中移除元素,如下代码会陷入死循环。
List<Integer> lstReviewTaskIds = new ArrayList<>();
lstReviewTaskIds.add(1);
lstReviewTaskIds.add(2);
lstReviewTaskIds.add(3);
lstReviewTaskIds.add(4);
lstReviewTaskIds.add(5);
List<Integer> checkedReviewTaskIds = new ArrayList<>();
Iterator<Integer> idsIterator = lstReviewTaskIds.iterator();
while (idsIterator.hasNext()) {//如果checkedReviewTaskIds为空,那么idsIterator.hasNext()总是为true
for (Integer checkedReviewTaskId : checkedReviewTaskIds) {
if (Objects.equals(checkedReviewTaskId, idsIterator.next())) {
idsIterator.remove();
}
}
}
System.out.println(JSON.toJSONString(lstReviewTaskIds));
查阅源码可知,在next方法中,会将指向下一个的指针+1,如果不执行,hasNext判断逻辑为是否等于list的size,这样就一直返回true.正确的方式是在for循环开始前获取id,Integer id=idsIterator.next();或者直接使用ArrayList提供的removeAll方法。
自己实现ArrayList
public class ArrayListReview<E> {
/**
* 容器数组
*/
private Object[] elementData;
/**
* 当前容器元素个数
*/
private Integer size = 0;
public ArrayListReview() {
this(8);
}
public ArrayListReview(int capacity) {
this.elementData = new Object[capacity];
}
public void add(E e) {
if (size >= elementData.length) {
//数组容器已满,需要扩容数组
this.grow();
}
elementData[this.size++] = e;
}
/**
* 扩容数组
*/
private void grow() {
int newLength = elementData.length + elementData.length >> 1;
this.elementData = Arrays.copyOf(this.elementData, newLength);
}
public void add(int index, E e) {
if (index >= this.size) {
throw new ArrayIndexOutOfBoundsException("数组下标越界");
}
if (size >= elementData.length) {
//扩容数据
this.grow();
}
int moveNum = (this.size - 1) - index + 1;
System.arraycopy(this.elementData, index, this.elementData, index + 1, moveNum);
this.elementData[index] = e;
size++;
}
@SuppressWarnings("unchecked")
public E remove(int index) {
E e = (E) this.elementData[index];
//向前迁移数据
System.arraycopy(this.elementData, index + 1, this.elementData, index, (this.size - 1) - index);
elementData[--size] = null;
return e;
}
public void printList() {
for (Object e : elementData) {
System.out.println(e);
}
}
}
测试代码
public class ArrayListReviewTest {
@Test
public void add() {
ArrayListReview<Integer> arrayListReview = new ArrayListReview<Integer>();
for (int i = 0; i < 17; i++) {
arrayListReview.add(i);
}
arrayListReview.printList();
}
@Test
public void add1() {
ArrayListReview<Integer> arrayListReview = new ArrayListReview<Integer>();
for (int i = 0; i < 4; i++) {
arrayListReview.add(i);
}
arrayListReview.add(3, 33);
}
@Test
public void remove() {
ArrayListReview<Integer> arrayListReview = new ArrayListReview<Integer>();
for (int i = 0; i < 4; i++) {
arrayListReview.add(i);
}
arrayListReview.remove(1);
}
}
- CopyOnWriteArrayList
初始化分配的数组空间大小为0
private transient volatile Object[] array;
存放的数组用volatile修饰,保证获取数组指针指向为最新的指向。
public boolean add(E e) {
final ReentrantLock lock = this.lock;
lock.lock();
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();
}
}
先上锁-》复制数据到之前数组+1的新数组中-》释放锁。
2022年2月16日更新
在遍历集合的时候同时修改容器
/**
* 没问题
*/
@Test
public void test01(){
List<String> list=new ArrayList<>();
list.add("0");
list.add("1");
list.add("2");
list.add("3");
list.add("4");
for (int i = 0; i < list.size(); i++) {
if("2".equals(list.get(i))){
list.remove(4);
}
}
System.out.println(JSON.toJSONString(list));
}
/**
* 使用迭代器-用迭代器中的remove,不会有问题
*/
@Test
public void test02(){
List<String> list=new ArrayList<>();
list.add("0");
list.add("1");
list.add("2");
list.add("3");
list.add("4");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()){
String s = iterator.next();
if(s.equals("2")){
iterator.remove();
}
}
System.out.println(JSON.toJSONString(list));
}
/**
* 使用迭代器-modCount和expectModCount不一致导致的异常
* java.util.ConcurrentModificationException
* at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901)
* at java.util.ArrayList$Itr.next(ArrayList.java:851)
* at com.txp.owner.basic.record.test202202.TestMain20220216.test03(TestMain20220216.java:73)
*/
@Test
public void test03(){
List<String> list=new ArrayList<>();
list.add("0");
list.add("1");
list.add("2");
list.add("3");
list.add("4");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()){
String s = iterator.next();
if(s.equals("2")){
list.remove(4);
}
}
System.out.println(JSON.toJSONString(list));
}
/**
* 本质用的迭代器
* java.util.ConcurrentModificationException
* at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901)
* at java.util.ArrayList$Itr.next(ArrayList.java:851)
* at com.txp.owner.basic.record.test202202.TestMain20220216.test02(TestMain20220216.java:41)
*/
@Test
public void test04(){
List<String> list=new ArrayList<>();
list.add("0");
list.add("1");
list.add("2");
list.add("3");
list.add("4");
for (String s : list) {
if("2".equals(s)){
list.remove(4);
}
}
System.out.println(JSON.toJSONString(list));
}
4 Vector
4.1 类说明:实现List接口,继承AbstractList,类中用数组的形式存储数据,Vector中的方法大部分都是线程安全。
The Vector class implements a growable array of objects. Like an array, it contains components that can be accessed using an integer index. However, the size of a Vector can grow or shrink as needed to accommodate adding and removing items after the code Vector has been created.
4.2 重要方法:
迭代遍历输出元素:
ListIterator e2 = ((List) o).listIterator();
while (e1.hasNext() && e2.hasNext()) {
E o1 = e1.next();
Object o2 = e2.next();
if (!(o1==null ? o2==null : o1.equals(o2)))
return false;
}