老哥你真的知道ArrayList#sublist的正确用法么

``````public List<Integer> trimList(List<Integer> list, int add) {
list.sort(null);
if (list.size() > 20) {
list = list.subList(0, 20);
}
return list;
}

1. 测试验证

``````@Test
public void testTri() throws InterruptedException {
List<Integer> list = new ArrayList<>(30);
Random random = new Random();
int cnt = 0;
while (true) {
list = trimList(list, random.nextInt(100000));

++cnt;
System.out.println(list + " >> " + cnt);
}
}

2. SubList 方法揭秘

``````public List<E> subList(int fromIndex, int toIndex) {
subListRangeCheck(fromIndex, toIndex, size);
return new SubList(this, 0, fromIndex, toIndex);
}

private class SubList extends AbstractList<E> implements RandomAccess {
private final AbstractList<E> parent;
private final int parentOffset;
private final int offset;
int size;

SubList(AbstractList<E> parent,
int offset, int fromIndex, int toIndex) {
this.parent = parent;
this.parentOffset = fromIndex;
this.offset = offset + fromIndex;
this.size = toIndex - fromIndex;
this.modCount = ArrayList.this.modCount;
}
...
}

``````public void add(int index, E e) {
checkForComodification();
this.modCount = parent.modCount;
this.size++;
}

3. 正确使用姿势

``````public List<Integer> trimList(List<Integer> list, int add) {
list.sort(null);
if (list.size() > 20) {
list = new ArrayList<>(list.subList(0, 20));
}
return list;
}

4. 知识点扩展

``````@ToString
public static class InnerC {
private String name;
private Integer id;

public InnerC(String name, Integer id) {
this.name = name;
this.id = id;
}
}

@Test
public void subList() {
List<Integer> list = new ArrayList<>();
for (int i = 0; i < 20; i++) {
}

// case 1
List<Integer> sub = list.subList(10, 15);
System.out.println("list: " + list);
System.out.println("sub: " + sub);

// case 2
list.set(11, 200);
System.out.println("list: " + list);
System.out.println("sub: " + sub);

// case 3
list = new ArrayList<>(sub);
sub.set(0, 999);
System.out.println("list: " + list);
System.out.println("sub: " + sub);

// case 4
List<InnerC> cl = new ArrayList<>();

List<InnerC> cl2 = new ArrayList<>(cl.subList(1, 3));
cl2.get(0).name = "a5";
cl2.get(0).id = 5;
System.out.println("list cl: " + cl);
System.out.println("list cl2: " + cl2);
}

• case1 执行之后相当于在list数组的下标15这里，插入数据100
• case2 执行之后，list的下标11，相当于sub的下标1，也就是说sub[1] 变成了200

``````public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// replace with empty array.
this.elementData = EMPTY_ELEMENTDATA;
}
}

// 对应的核心逻辑就在 Arrays.copyOf，而这个方法主要调用的是native方法`System.arraycopy`

public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
@SuppressWarnings("unchecked")
T[] copy = ((Object)newType == (Object)Object[].class)
? (T[]) new Object[newLength]
: (T[]) Array.newInstance(newType.getComponentType(), newLength);
System.arraycopy(original, 0, copy, 0,
Math.min(original.length, newLength));
return copy;
}

``````list: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 100, 15, 16, 17, 18, 19]
sub: [10, 11, 12, 13, 14, 100]
list: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 200, 12, 13, 14, 100, 15, 16, 17, 18, 19]
sub: [10, 200, 12, 13, 14, 100]
list: [10, 200, 12, 13, 14, 100]
sub: [999, 200, 12, 13, 14, 100]
list cl: [BasicTest.InnerC(name=a, id=1), BasicTest.InnerC(name=a5, id=5), BasicTest.InnerC(name=a3, id=3), BasicTest.InnerC(name=a4, id=4)]
list cl2: [BasicTest.InnerC(name=a5, id=5), BasicTest.InnerC(name=a3, id=3)]

• 数组内为Integer时，两者互不影响
• 数组内为普通对象时，修改其中一个，会影响另外一个

0条评论