List
Vector
- Vector底层维护一个Object类型数组elementData
protected Object[] elementData;
- 线程安全的,Vector类的操作方法带有synchronized
public synchronized boolean add(E e) {
modCount++;
ensureCapacityHelper(elementCount + 1);
elementData[elementCount++] = e;
return true;
}
示例代码:
Vector<Integer> vector = new Vector<>();
vector.add(1);
vector.add(2);
vector.add(3);
vector.add(null);
vector.add(null);
System.out.println(vector);
结果输出:
[1, 2, 3, null, null]
ArrayList
底层结构与源码分析之扩容机制
- ArrayList底层维护一个Object类型数组elementData
transient Object[] elementData;
- 当创建ArrayList对象时,如果使用的是无参构造器,则初始化elementData容量为0,第一次添加,则扩容elementData为10,如果再次扩容,则扩容elementData为1.5倍
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
// 当创建ArrayList对象时,如果使用的是无参构造器,则初始化elementData容量为0
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
/**
* Default initial capacity.
*/
private static final int DEFAULT_CAPACITY = 10;
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
// 第一次添加,则扩容elementData为10
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
// 如果再次扩容,则扩容elementData为1.5倍
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容量为指定大小,如果需要扩容,则直接扩容elementData为1.5倍
示例代码:
// 使用无参构造器,初始化elementData容量为0
List<Integer> list = new ArrayList<>();
for (int i = 1; i <= 10; i++) {
// i==1 第一次添加,则扩容elementData为10
list.add(i);
}
for (int i = 1; i <= 15; i++) {
// i==1 如果再次扩容,则扩容elementData为1.5倍
list.add(i);
}
list.add(100);
list.add(200);
list.add(null);
list.add(null);
System.out.println(list);
结果输出:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 100, 200, null, null]
LinkedList
- LinkedList底层维护一个双向链表,其中first和last两个属性分别指向首节点和尾节点。每个节点(Node对象)维护prev、next、item三个属性。
- 添加和删除元素操作,效率高
示例代码:
LinkedList<Integer> linkedList = new LinkedList<>();
linkedList.add(1);
linkedList.add(2);
linkedList.add(3);
linkedList.add(null);
linkedList.add(null);
System.out.println(linkedList);
结果输出:
[1, 2, 3, null, null]
Vector和ArrayList比较
ArrayList和LinkedList比较
如何选择?
- 查询,修改操作多,选择ArrayList
- 增加,删除操作多,选择LinkedList
- 一般情况下,在程序中多数情况下都是查询操作,因此大部分情况下会选择ArrayList
- 根据业务情况灵活选择
Set
HashSet
- 可以存放null,但只能存放一个null
- 不能有重复元素
- 不保证存放元素的顺序和取出顺序是一致的(可用linkedHashSet保证存放和取出的顺序一致)
示例代码:
HashSet set = new HashSet<>();
System.out.println(set.add(new String("lxw")));//true
System.out.println(set.add(new String("lxw")));//false,加入不了
结果分析:
String
重写了 hashCode
方法,其 hashCode
值是由内容决定的,而不是地址决定的。所以两次new String("lxw"),返回了两个不同引用的对象地址,但这两个引用指向同一内容,所以引用地址不同,但hashcode相同的。
实现机制
- HashSet底层实现是HashMap
public HashSet() {
map = new HashMap<>();
}
- 添加一个元素时,由hash值转换成索引值
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
- 在存储数据表table,判断索引位置是否已存放有元素,如果没有,直接加入;如果有,调用equals比较,相同则丢弃,不同则添加
- 在Java8中,当一个链表的元素个数超过8,table>=64,会进化成红黑树。否则,采用数组扩容机制。
public class HashSetDemo {
static class A {
private int i;
public A(int i) {
this.i = i;
}
@Override
public int hashCode() {
return i;
}
}
public static void main(String[] args) {
HashSet<A> set = new HashSet<>();
for (int i = 1; i <= 12;i++) {
set.add(new A(i));
}
//单链表为8
for (int i = 1; i <= 7; i++) {
set.add(new A(1));
}
//单链表为9
for (int i = 1; i <= 8; i++) {
set.add(new A(2));
}
System.out.println();
}
}
LinkedHashSet
- LinkedHashSet是HashSet的子类
public class LinkedHashSet<E>
extends HashSet<E>
implements Set<E>, Cloneable, java.io.Serializable {
// ...
}
- LinkedHashSet底层是一个LinkedHashMap,底层维护数组+双向链表
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
map = new LinkedHashMap<>(initialCapacity, loadFactor);
}
- LinkedHashSet根据元素的hashCode值决定元素的存储位置,同时使用链表维护元素的次序,使元素看起来是以插入顺序保存的
TreeSet
- 底层实现是TreeMap
public TreeSet() {
this(new TreeMap<E,Object>());
}
2.排序的