您的位置:首页 > 编程语言 > Java开发

Java总结<四>集合框架

2012-10-07 22:04 405 查看
Java的集合大致可分为:SetListMap三种体系,其中Set代表无序、不可重复的集合;List代表有序、重复的集合;而Map则代表具有映射关系的集合。从JDK1.5以后,Java集合又增加了Queue体系集合,代表一种队列集合实现

Java的集合类主要由两个接口派生而出:Collection和Map

下图是Collection接口的实现类和子接口的继承关系



图中颜色部分是比较常用的实现类:HashSet和ArrayList

Set接口

Set集合是不允许包含相同的元素的,是根据equals()来判断是否是同一对象

HashSet是Set接口的典型实现,HashSet是按Hash算法来存储集合中的元素的,因此具有很好的存取和查找性能。

HashSet有以下特点:

不能保证元素的排序顺序

不是同步

集合元素值可以为null

存入一个新元素,要判断是否已经存在的标准是两个对象通过equals()比较相等,并且两个对象的hashCode()方法返回值也相等。如果需要某个类的对象保存到HashSet集合中,重写这个类的equals方法和hashCode方法时,应该尽量保证两个对象通过equals比较结果跟hashCode返回结果一致(hashCode的对象的放置位置,而equals是判断两个对象是否的同一个,如果hashCode一样,但是equals不同,则会出现两个不同的元素放同一个位置,反过来的情况更加糟糕)

LinkedHashSet则是继承了HashSet的子类,使用的是链表结构。也是根据hashCode值来决定元素存储位置,但它同时使用链表维护元素的次序,但是由于要维护元素的插入顺序,故性能略低于HashSet的性能

TreeSet采用红黑树的数据结构对元素进行排序。默认情况下是升序的自然排序,也可以定制排序。当加入一个对象进TreeSet集合中时,TreeSet调用该对象的compareTo(Object obj)方法与容器中的其他对象比较大小,然后根据红黑树算法决定它的存储位置。

EnumSet的集合元素也是有序的,是以枚举值在Enum类内的定义顺序来决定集合元素的顺序。在内部以位向量的形式存储所以EnumSet对象占用内存很小,而且运行效率很好。尤其是进行批量操作时。

总结:

如何选择HashSet和TreeSet,HashSet的性能总是比TreeSet好(特别是最常用的添加、查询元素等操作),因为TreeSet需要额外的红黑树算法来维护集合元素的次序。只有当需要一个保持排序的Set时,才应该使用TreeSet,否则都应该使用HashSet。而HashSet的子类LinkedHashSet,对普通的插入、删除操作,LinkedHashSet比HashSet要稍微慢一点(维护链表开销),但是遍历会更快

EnumSet是所有Set实现类中性能最好的。

以上都不是线程安全的,如果多线程访问,可以用Collections工具类的synchronizedSortedSet方法来“包装”该Set集合。此操作最好在创建时进行,如

SortedSet s = Collections.synchronizedSortedSet(new TreeSet(...));

List接口

List集合代表一个有序集合,默认是按照元素的添加顺序设置元素的索引

ArrayList、Vector和LinkedList

(1)ArrayList:实现:默认创建一个大小为10Object数组,每次add的时候,有一个minCapacity变量,每次都加1,然后和Object数组的大小比较,如果大于则将当前的Object数组值赋值给一个数组对象,接着产生一个新的数组的容量值(此值计算方法为当前数组大小*1.5+1,如果还小于minCapacity那么就以minCapacity作为新的容量值),得到这个容量值后调用Arrays.copyOf来生成新的数组对象,如果想调整增加策略,可继承ArrayList,并覆盖ensureCapacity方法

补充:

其中的Arrays.coryOf是这样实现的,首先创建一个新的数组,该数组对象的类型和之前ArrayList中元素的类型一致的,在这里JDK做了小优化,在创建完新的数组之后调用System.arraycopy通过native方法将之前数组中的对象复制到新的数组中

ArrayList还提供了add(int,E)方法,跟add()方法的区别是将当前数组对象进行一次复制,即将目前的index及其后的数据往后挪动一位,故要多付出一次复制数组的代价

(2)Vector线程安全的,和ArrayList一样是采用Object数组实现的,Vector()调用也创建一个大小为10Object数组,并将capacityIncrement设置为0,但是add的时候是不一样的,Vector的add方法加了synchronized关键字,而且当容量不够时进行扩容的策略不一样,Vector的策略是:如果容量不够,那么如果capcacityIncrement大于0,则将Object数组的大小扩为现有size+capcacityIncrement,如果capcacityIncrement小于0,则Object数组的大小扩为现有size的两倍

(3)LinkedList是基于双向链表机制,add是使用头插法

待续..................
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: