java容器比较_Java中各种容器比较

Collection List

Collection 是 Java 集合的一个根接口,JDK 没有它的实现类。 内部仅仅做 add(),remove(),contains(),size() 等方法的声明。

List 接口是Collection 接口的一个子类,在Collection 基础上扩充了方法。同时可以对每个元素插入的位置进行精确的控制,它的主要实现类有 ArrayList,Vector,LinkedList。

这里需要注意的是,List 接口的实现类

插入的值允许为空,也允许重复。

插入的值允许为空,也允许重复。

插入的值允许为空,也允许重复。

ArrayList

ArrayList 实现了 List 接口,意味着可以插入空值,也可以插入重复的值,非同步 ,它是基于数组 的一个实现。

部分成员变量如下:

//默认初始值

private static final int DEFAULT_CAPACITY = 10

//存放数据的数组

transient Object[] elementData;

这里可以看出,elementData 提示了是基于数组的实现, DEFAULT_CAPACITY 指名了默认容量为 10 个。

下面重点理解 add()方法,这将有助于理解 ArrayList 的应用场景和性能消耗:

add():

public booleanadd(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++;

if(minapacity - elementData.length > 0)

grow(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);

elementData = Arrays.copyOf(elementData, newCapacity);

}

这里可以看到,进行一个 add()方法,首先通过 ensureCapacityInternal(size + 1); 判断需不需要扩容;然后再进行 elementData[size++] = e。 插入的时间复杂度O(1)。是非常高效的。

那么网上很多说 ArrayList 不适合 增删操作非常多的操作,这是怎么回事呢?首先可以看到这句话:elementData = Arrays.copyOf(elementData, newCapacity); 需要知道的是, Arrays.copyOf 函数的内部实现是再创建一个数组,然后把旧的数组的值一个个复制到新数组中。当经常增加操作的时候,容量不够的时候,就会进行上述的扩容操作,这样性能自然就下来了。

但是

谁让你不初始化最小容量

谁让你不初始化最小容量

谁让你不初始化最小容量

ArrayList 的默认容量是 10 个,如果你本身的数据有 100 个,但是你没进行初始化最小容量,用完10 个,马上就扩容,性能就会马上下降。如果你进行了初始化,指定了最小容量 101 个,那么就不可能会扩容,此时就几乎没有什么性能消耗的问题的。

所以,下次使用 ArrayList 的时候,记得初始化最小容量,除非你本身的数据就小于 10 个,如下代码:

ArrayList arrayList = new ArrayList(20);

总结:

ArrayList 可以插入空值,也可以插入重复值

ArrayList 是基于数组的时候,所以很多数组的特性也直接应用到了 ArrayList。

ArrayList 的性能消耗主要来源于 扩容。

ArrayList 创建的时候 需要考虑是否要初始化最小容量,以此避免扩容带来的消耗。

Vector

上述的 ArrayList 不是线程安全的。那么 Vector 就可以看作是 Vector 的一个线程安全版本。由于也是实现了 List 接口,所以也是 可以插入空值,可以插入重复的值。

内部成员变量:

protectedObject[] elementData;publicVector() {this(10);

}

可以看到,也是基于 数组的实现,初始化也是 10 个容量。 那么,再来看看 add()方法是否和 ArrayList 相同。

public synchronized booleanadd(E e) {

modCount++;

ensureCapacityHelper(elementCount+ 1);

elementData[elementCount++] =e;return true;

}

可以看到,和 ArrayList 也是一样的,只是加了 synchronized 进行同步, 其实很多其他方法都是通过加 synchronized 来实现同步。

总结:

可以插入空值,也可以插入重复值

也是基于数组的时候,所以很多数组的特性也直接应用到了 VVector。

性能消耗也主要来源于 扩容。

创建的时候 需要考虑是否要初始化最小容量,以此避免扩容带来的消耗。

相当于 ArrayList 的线程安全版本,实现同步的方式 是通过 synchronized。

LinkedList

LinkedList 实现了 List 接口,所以LinkedList 也可以放入重复的值,也可以放入空值。LinkedList不支持同步。LinkedList 不同于ArrayList 和Vector,它是使用链表的数据结构,不再是数组。

成员变量:

transient int size = 0; //数量

transient Node first; //首节点

transient Node last; //最后节点

private static class Node{

E item;

Nodenext;

Nodeprev;

Node(Node prev, E element, Nodenext) {this.item =element;this.next =next;this.prev =prev;

}

}

那么,在进行 add() 方法的时候:

public booleanadd(E e) {

linkLast(e);return true;

}voidlinkLast(E e) {final Node l =last;final Node newNode = new Node<>(l, e, null);

last=newNode;if (l == null)

first=newNode;elsel.next=newNode;

size++;

modCount++;

}

当进行增删的时候,只需要改变指针,并不会像数组那样出现整体数据的大规模移动,复制等消耗性能的操作。

ArrayList,Vector,LinkedList 的整体对比

实现方式:

ArrayList,Vector 是基于数组的实现。

LinkedList 是基于链表的实现。

同步问题:

ArrayList,LinkedList 不时候线程安全的。

Vector 是线程安全的,实现方式是在方法中加 synchronized 进行限定。

适用场景和性能消耗

ArrayList 和 Vector 由于是基于数组的实现,所以在固定位置插入,固定位置删除这方面会直接是 O(1)的时间复杂度,但是可能会出现扩容的问题,这是非常消耗性能的。

LinkedList 不会出现扩容的问题,所以比较适合增删的操作。但是由于不是数组的实现,所以在 定位方面必须使用 遍历的方式,这也会有 O(n)的时间复杂度

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值