集合分有序无序,也可分允许重复和不允许重复。
| 集合名称 | 简介 | remark |
|---|---|---|
| ArrayList | 基于数组,查询快,增删慢,可重复,线程不安全,效率高 | 插入元素时需要扩容,LinkedList不需要 |
| LinkedList | 基于链表,查询慢,增删快,可重复,线程不安全,效率高 | 不要循环获取LinkedList中的元素 |
| HashSet | 无序,线程不安全,允许null值,元素不允许重复 | |
| TreeSet | 有序,线程不安全,不允许null值,元素不允许重复 | 默认升序 |
List 继承了 Collection,ArrayList、LinkedList 实现了 List。
Set 继承了 Collection,HaseSet、TreeSet、LinkedHashSet 从 Set 中衍生而出。
ArrayList 与 LinkedList 性能对比
一味地说 ArrayList 的增删操作比 LinkedList 的增删快,是不对的。
/**
* 代码运行环境:win10, JDK8, AMD R7 4800H
*/
public static void main(String[] args) {
int count = 10000000;
ArrayList<Integer> array = new ArrayList<>();
LinkedList<Integer> linked = new LinkedList<>();
long begin = System.currentTimeMillis();
for (int i = 0; i < count; i++) {
array.add(i);
}
System.out.println("ArrayList add " + count + " num cost time : " + (System.currentTimeMillis() - begin));
begin = System.currentTimeMillis();
for (int i = 0; i < count; i++) {
linked.add(i);
}
System.out.println("LinkedList add " + count + " num cost time : " + (System.currentTimeMillis() - begin));
}
运行代码,从控制台中可以看到两个列表添加10000000个参数的耗时:
ArrayList add 10000000 num cost time : 4255
LinkedList add 10000000 num cost time : 7929
相反,ArrayList 增删的效率比 LinkedList 的效率还要高。
如果是从头部插入,理论上 LinkedList 的效率比 ArrayList 高。LinkedList 提供 addFirst 方法,链表速度快。ArrayList 则还涉及到拷贝和扩容。
比较 LinkedList 和 ArrayList 的效率,需要结合数量以及增删的位置(头、尾、中间)来判断。
LinkedList 和 ArrayList 到底谁快可以参考:www.cnblogs.com/xiaofuge/p/…
HashSet 和 TreeSet
HashSet 如何做到集合中元素不重复?
HashSet 先获取对象的 HashCode,根据 HashCode 决定元素的存储位置。如果两个对象相等,即 ObjA.equals(ObjB),但 ObjA 和 ObjB 的 HashCode 不相等,也可以存放在同一个 HashSet 中。
/**
* 构造对象,重写 equals 方法,制作两个对象相等但hashCode不相等的情况
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class CommonBeanReWrite {
private Integer integer;
private Long aLong;
@Override
public boolean equals(Object obj) {
CommonBeanReWrite commonBean = (CommonBeanReWrite) obj;
return this.aLong.equals(commonBean.getALong());
}
}
// 测试代码
private void testHashSetElementUnique() {
HashSet<CommonBeanReWrite> hashSet = Sets.newHashSet();
CommonBeanReWrite bean1 = CommonBeanReWrite.builder().integer(1).aLong(1L).build();
CommonBeanReWrite bean2 = CommonBeanReWrite.builder().integer(2).aLong(1L).build();
System.err.println("两个对象是否相等: " + bean1.equals(bean2));
System.err.println("对象1的hashCode:" + bean1.hashCode());
System.err.println("对象2的hashCode:" + bean2.hashCode());
hashSet.add(bean1);
hashSet.add(bean2);
System.out.println("hashSet中元素的个数: " + hashSet.size());
}
运行代码观察控制台输出结果
两个对象是否相等: true
hashSet中元素的个数: 2
对象1的hashCode:263025902
对象2的hashCode:438135304
两个对象相等(即A.equals(B)),但 HashCode 不相等,故可以共同存放在同一个 HashSet 中。
TreeSet 的排序
TreeSet 默认是升序,但是新建 TreeSet 时可以指定排序方式。
// 默认升序
private void testTreeSetDefaultSort() {
TreeSet<Integer> treeSet = Sets.newTreeSet();
treeSet.add(100);
treeSet.add(50);
treeSet.add(200);
treeSet.add(150);
treeSet.forEach(item -> System.out.print(item + "\t"));
}
运行后控制台输出结果可以看出,TreeSet 默认的排序方式是升序
50 100 150 200
TreeSet 也可以设置自定义的排序规则、
// 设置降序
private void testTreeSetCustomizeSort() {
TreeSet<Integer> treeSet = new TreeSet<>((o1, o2) -> {
if(o1.equals(o2)){
return 0;
} else if (o1 > o2) {
return -1;
} else {
return 1;
}
});
treeSet.add(100);
treeSet.add(50);
treeSet.add(200);
treeSet.add(150);
treeSet.forEach(item -> System.out.print(item + "\t"));
}
运行后通过控制台输出可以看出,TreeSet 按照自定义的排序方式进行存储
200 150 100 50