在Java实际开发中,我们会常常用到容器,那么各种容器类我们该如何进行抉择呢?在这里进行一个简单的总结。
1、对List的选择
对于随机访问的get()和set()操作,背后有数组支撑的List仅仅ArrayList稍微快一点,但是对于LinkedList,相同的操作会产生高昂的性能消耗,因为它本身就不是针对随机访问操作而设计的。
避免使用Vector,它只是存在于支持遗留代码的类库中。最佳的做法就是将ArrayList作为默认首选,只有当你需要使用额外的功能的时候,或者当程序的性能因为经常进行插入和删除操作而变差的时候,就去选择LinkedList。如果元素的数量确定,那么我们既可以选择List,也可以选择真正的数组。
如果是在多线程环境下呢?我们选择CopyOnWriteArrayList!
补充:List有序。
package com.tu.test;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
public class ListTest {
public static void main(String[] args){
System.out.println("ArrayList:");
List
myList.add("WuHoujian");
myList.add(null);
myList.add(null);
System.out.println(myList.toString());
System.out.println("index of null is :" + myList.indexOf(null));
System.out.println("LinkedList:");
LinkedList
myLinkedList.addFirst("test11");
myLinkedList.addFirst("test22");
myLinkedList.addFirst(null);
myLinkedList.addFirst(null);
System.out.println(myLinkedList.toString());
System.out.println("index of null is :" + myLinkedList.indexOf(null));
}
}
输出:
ArrayList:
[WuHoujian, null, null]
index of null is :1
LinkedList:
[null, null, test22, test11]
index of null is :0
2、对Set的选择
HashSet的性能基本上总是比TreeSet好,特别是在添加和查询元素的时候。那什么时候我们应该选择TreeSet呢?当我们需要一个排好序的Set时,就选择TreeSet,因为其内部结构支持排序。
LinkedHashSet和HashSet呢?由于LinkedHashSet是由链表实现的,插入删除元素操作需要更高的代价,所以我们也需要结合具体的场景进行选择(类似LinkedList和ArrayList)。
补充:Set的底层实现是基于Map实现的,HashSet底层是HashMap,TreeSet底层是TreeMap。从下面代码我们可以看出,HashSet是无序的,TreeSet会进行排序。
package com.tu.test;
import java.util.HashSet;
import java.util.Set;
import java.util.TreeSet;
public class SetTest {
public static void main(String [] args){
System.out.println("HashSet:");
Set
set1.add("test111");
set1.add("test222");
set1.add("test333");
System.out.println(set1.toString());
System.out.println(set1.iterator().next());
System.out.println("TreeSet:");
TreeSet
set2.add("a4");
set2.add("a2");
set2.add("a5");
System.out.println(set2.toString());
}
}
输出:
HashSet:
[test222, test111, test333]
test222
TreeSet:
[a2, a4, a5]
3、对Map的选择
排除IdentityHashMap,所有的Map实现的插入操作都会随着Map尺寸的变大而明显变慢。
Hashtable的性能和HashMap大体上相当,因为HashMap是用来代替Hashtable的。那么它们两者之间有什么区别呢?主要有三点:第一点就是Hashtable是基于旧的Dictionary实现的,而HashMap是Map接口的实现;第二点就是Hashtable是同步的,在多线程环境中使用,而HashMap不是同步的;第三点不同就是HashMap可以允许一个key为null,任意个value为null。
TreeMap通常比HashMap要慢。同TreeSet一样,TreeMap是一种创建有序列表的表达方式。
LinkedHashMap在插入时比HashMap慢一点,因为它除了维护散列数据结构之外,还需要维护链表结构。
补充:从下面的Demo以及输出结果可以看出,在Map中null元素永远被放在第一个元素;另外当键值相同时,表面上看到的是覆盖,底层实际上依旧保持着原有的数据。看了源代码会知道,Map底层是基于数组实现,数组类型是Entry类型,包括key,value,next和hash几个属性,当有重复的键值(准确地说是key的hash值),原有的值value会被放到Entry的next属性中,这样也解决了Map的冲突问题。
package com.tu.test;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
public class MapTest {
public static void main(String[] args) {
Map
map1.put("name", "WuHoujian");
map1.put(null, "I'm null");
Object str = map1.put("name", "William");
System.out.println("有两个相同的key,前一次的值为:" + str);
int i = 1;
for (Entry
System.out.println("map中第" + i +"元素:" + entry.getKey() + "=" + entry.getValue());
i++;
}
}
}
输出:
有两个相同的key,前一次的值为:WuHoujian
map中第1元素:null=I'm null
map中第2元素:name=William
注:以上提到的各种容器类,大家如果感兴趣,可以多看看底层源代码的实现,深入了解一下各自的实现,对它们有一个更深刻的认识。
阅读源码之后的心得,大家后面可以分享一下