数学上,序列是被排成一列的对象(或事件);这样,每个元素不是在其他元素之前,就是在其他元素之后。这里,元素之间的顺序非常重要。容量是一个很需要平衡的数值。
我们以List的实现类ArrayList为例,观察一下容量的增长。
ArrayList默认的是10,如果我们改小成1,将会发现我们除了第一个不需要增加容量,
每增加一个 我们都需要进行扩容数组
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(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);
}
重点在这里
elementData = Arrays.copyOf(elementData, newCapacity);
所以我们在应用该类的时候,要特别注意存储之前的准备工作,我们可以提前做好容量的规划,然后改变默认值,间接也提升了我们代码的效率。
我们观察了几种列表,发现基于数组的序列,数据结构最简单,我们应该首先考虑使用该类,linkedList的数据结构是多个节点连接,每个节点都有两个指针,一个指向上一个节点,一个
指向下一个节点。
我们做了一个试验,
List list = new ArrayList();
long begin = System.currentTimeMillis();
for(int i= 0;i<1000000;i++){
list.add(i);
}
System.out.println(System.currentTimeMillis() - begin);
LinkedList<Integer> list = new LinkedList<Integer>();
long begin = System.currentTimeMillis();
for(int i= 0;i<1000000;i++){
list.add(i);
}
System.out.println(System.currentTimeMillis() - begin);
所消耗的时间差了一倍,
两者唯一相像的地方是删除元素后,都是真实的空间容量大小。
Vector 的默认空间是10,vector的大小可以根据需要增大或缩小,以适应创建 Vector 后进行添加或移除项的操作。 这里所说的大小是实际元素的大小,而不是空间的大小。
我们做个试验
MyVector<String> ve = new MyVector<String>();
ve.add("1");
ve.add("2");
ve.add("3");
ve.add("4");
ve.add("5");
ve.add("6");
ve.add("7");
ve.add("8");
ve.add("9");
ve.add("10");
ve.add("11");
ve.remove(3);
在删除索引为3的列之后,整个vector实际元素为
1 2 3 5 6 7 8 9 10 11,而且被删除元素的位置都被直接填充了,后面的所有元素直接向前移。
这个向前异动的操作,使用了System.arraycopy(elementData, index+1, elementData, index,numMoved);
我们观察了一下,整个数据空间没有发生改变,容量都是20,但实际的元素由11变成10了。
我们以List的实现类ArrayList为例,观察一下容量的增长。
ArrayList默认的是10,如果我们改小成1,将会发现我们除了第一个不需要增加容量,
每增加一个 我们都需要进行扩容数组
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(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);
}
重点在这里
elementData = Arrays.copyOf(elementData, newCapacity);
所以我们在应用该类的时候,要特别注意存储之前的准备工作,我们可以提前做好容量的规划,然后改变默认值,间接也提升了我们代码的效率。
我们观察了几种列表,发现基于数组的序列,数据结构最简单,我们应该首先考虑使用该类,linkedList的数据结构是多个节点连接,每个节点都有两个指针,一个指向上一个节点,一个
指向下一个节点。
我们做了一个试验,
List list = new ArrayList();
long begin = System.currentTimeMillis();
for(int i= 0;i<1000000;i++){
list.add(i);
}
System.out.println(System.currentTimeMillis() - begin);
LinkedList<Integer> list = new LinkedList<Integer>();
long begin = System.currentTimeMillis();
for(int i= 0;i<1000000;i++){
list.add(i);
}
System.out.println(System.currentTimeMillis() - begin);
所消耗的时间差了一倍,
两者唯一相像的地方是删除元素后,都是真实的空间容量大小。
Vector 的默认空间是10,vector的大小可以根据需要增大或缩小,以适应创建 Vector 后进行添加或移除项的操作。 这里所说的大小是实际元素的大小,而不是空间的大小。
我们做个试验
MyVector<String> ve = new MyVector<String>();
ve.add("1");
ve.add("2");
ve.add("3");
ve.add("4");
ve.add("5");
ve.add("6");
ve.add("7");
ve.add("8");
ve.add("9");
ve.add("10");
ve.add("11");
ve.remove(3);
在删除索引为3的列之后,整个vector实际元素为
1 2 3 5 6 7 8 9 10 11,而且被删除元素的位置都被直接填充了,后面的所有元素直接向前移。
这个向前异动的操作,使用了System.arraycopy(elementData, index+1, elementData, index,numMoved);
我们观察了一下,整个数据空间没有发生改变,容量都是20,但实际的元素由11变成10了。