浏览一下Java容器的简图,可以看到,其实只有四种容器:Map、List、Set和Queue(Queue不在其中)。其中Set代表无序、不可重复的集合;List代表有序、重复的集合;而Map则代表有映射关系的集合,Java5又增加了Queue体系集合,代表一种队列集合实现。
HashSet和TreeSet是Set的两个典型实现,到底如何选择HashSet和TreeSet呢?HashSet的性能总是比TreeSet好(特别是最常用的添加、查询元素操作),因为TreeSet需要额外的红黑树算法来维护集合元素的次序。只有当需要一个保持排序的Set时,才应该使用TreeSet,否则都应该使用HashSet。
因为这四种容器都实现了Collection接口,所以它们都可以向上转型为Collection,类似于这样写:Collection ll = new Map();这样我们可以充分利用多态特性进行代码复用。
面试时的一个常见问题是:ArrayList和Vector的区别是什么?你可以这样说:ArrayList是线程不安全的,当多个线程访问同一个ArrayList集合时,如果有超过一个线程修改了ArrayList集合,则程序必须手动保证该集合的同步性;但Vector集合则是线程安全的,无须程序保证该集合的同步性,但Vector是一个古老的集合(从JDK1.0就有了),具有很多缺点,通常尽量少用Vector实现类。那么我们既要用ArrayList,又需要线程安全,该怎么办呢?那么我们就需要用到同步控制。
Collections类中提供了多个synchronizedXxx()方法,该方法可以将指定集合包装成线程同步的集合,从而可以解决多线程并发访问集合时的线程安全问题。
Java中常用的集合框架中的实现类HashSet、TreeSet、ArrayList、ArrayDeque、LinkedList、HashMap和TreeMap都是线程不安全的。如果有多个线程访问它们,而且有超过一个的线程试图修改它们,则存在线程安全的问题。Collections提供了多个类方法可以把它们包装成线程同步的集合。
下面的示例程序创建了4个线程安全的集合对象。
public class SynchronizedTest
{
public static void main(String[] args)
{
//下面程序创建了4个线程安全的集合对象
Collection c = Collections.synchronizedCollection(new ArrayList());
List list = Collections.synchronizedList(new ArrayList());
Set s = Collections.synchronizedSet(new HashSet());
Map m = Collections.synchronizedMap(new HashMap());
}
}
在上面示例程序中,直接将新创建的集合对象传给了Collections的synchronizedXxx方法,这样就可以直接获取List、Set和Map的线程安全实现版本了。