Java集合

来源:互联网 发布:当代大学生创业数据 编辑:程序博客网 时间:2024/06/11 11:32
集合类位于java.util包下,体系结构:Java集合主要由两个接口派生而出,Collection和Map。Set和List接口是Collection
接口派生出来的两个子接口,分别代表无序集合和有序集合,Queue是Java提供的队列实现。Map实现类用于保存具有影射关系
的数据(key-value对)。Java集合分三大类,Set无法记住添加顺序,元素不能重复,只能根据元素本身访问;List记住添加顺序,
长度可变,可以直接根据索引访问;Map可根据key访问value。Java集合常用的实现类:HashSet,TreeSet,ArrayList,ArrayDeque
LinkedList和HashMap,TreeMap。
Collection接口是List,Set和Queue接口的父接口,定义了一些集合操作的方法:Iterator iterator() 返回Iterator对象遍历元素
Iterator接口隐藏了各种Collection实现类的底层细节,提供程序遍历集合的统一编程接口,接口定义了如下三个方法
boolean hasNext(),Object next(),void remove()
使用Iterator迭代时,并不是把集合元素传递给迭代变量,只是值传递,所以修改迭代变量的值对集合无影响;
当迭代访问集合元素时集合里的元素不能被改变,只有Iterator的remove方法可以,否则引发java.util.Concurrent.ModificationException异常。
foreach循环遍历集合元素,与Iterator接口迭代访问集合元素是类似的,值传递给迭代变量,集合不能改变否则引发异常。
8.3.1 HashSet
HashSet按照Hash算法来存储集合中的元素,因此具有良好的存取和查找性能,有以下特点
不能保证元素的排列顺序,不是同步的(线程不安全),集合元素值可以为null
当向HashSet集合存入一个元素时,HashSet会调用该对象的hashCode()方法来得到该对象的hashCode值,然后根据
该HashCode值决定该对象在HashSet中的存储位置。
HashSet集合判断两个元素相等的标准是两个对象通过equal方法比较相等,且两个对象的hashCode方法返回值也相等
当把一个对象放入HashSet中时,如果需要重写该对象对应类的equal()方法,则也应该重写其hashCode()方法。
规则是:如果两个对象通过equal()比较返回true,这两个对象的hashCode值也应该相同。
如果equal()返回true,hashCode()返回值不同,将导致相同的对象存在hash表的不同位置,与Set规则有出入
如果equal()返回false,hashCode()返回值相同,HashSet会在这个位置用链式结构保存多个对象,HashSet访问元素时
根据元素的hashCode值快速定位的,导致访问集合元素性能下降
重写hashCode()方法的基本规则:
同一对象多次调用hashCode()方法应返回相同的值
两个对象通过equal()方法比较返回true时,这两个对象的hashCode()方法应返回相等的值
对象中用作equal()方法比较标准的Field,都应该用来计算hashCode值。每个Field计算一个int类型的hashCode,然后多个
Field的hashCode值相加计算一个总的hashCode,为避免直接相加偶然相等,可以为每个Field的hashCode乘以一个质数后相加
注意向hashSet中添加可变对象时要小心
8.3.2 LinkedHashSet
LinkedHashSet也是根据元素的hashCode值决定元素的存储位置,但它同时使用链表维护元素的次序。当遍历LinkedHashSet
将按元素的添加顺序来访问集合里的元素。因为LinkedHashSet需要维护元素的插入顺序,因此性能略低于HashSet的性能,
但在迭代访问set里的全部元素时会有很好的性能。
8.3.3 TreeSet
TreeSet是SortedSet接口的实现类,TreeSet可以确保集合元素处于排序状态
TreeSet采用红黑树的数据结构来存储集合元素,TreeSet排序规则:自然排序和定制排序
自然排序:
TreeSet会调用集合元素的compareTo(Object obj)方法比较元素间的大小关系,然后升序排列
java提供了Comparable接口,该接口里定义了一个compareTo(Object obj)方法,返回一个整数值,实现该接口的类必须实现该方法
obj1.compareTo(obj2)返回 0 对象相等; obj1大于obj2 返回 正整数; obj1小于obj2 返回 负整数
java 一些长用类实现了Compareble接口,并提供了比较大小的标准:BigDecimal,BigInteger以及所有数值类型对应的类
按数值大小比较,Character按字符的UNICODE值进行比较,Boolean中true大于false,String按字符串中字符的UNICODE比较
Date,Time按照时间大小比较。
加入TreeSet的对象的类必须实现Comparable接口,否则将引发ClassCastException异常
向TreeSet中添加的应该是同一个类的对象或者重写compareTo()方法,否则将引发ClassCastException异常
TreeSet判断对象是否相等的唯一标准:两个对象通过compareTo()方法比较是否返回0;
当需要把一个对象放进TreeSet中,重写该对象对应类的equal()方法,保证equal()返回true时,compareTo返回0
向TreeSet加入可变对象,后修改了该可变对象的Field,但TreeSet不会改变其顺序,导致元素处于无序状态,
可以删除没有被修改Field,且不与被修改Field的对象重复的对象,不可以删除修改了Field导致与其他对象重复的
对象,甚至集合中原有、Field没有被修改但与修改后元素相等的元素也无法删除
推荐HashSet和TreeSet只放不可变对象,保证程序健壮性。
定制排序:
需要在创建TreeSet集合对象时,提供一个Comparator对象与该TreeSet集合关联(Comparator的匿名内部类),有
该Comparator对象负责集合元素的排序逻辑。
8.3.4 EnumSet
EnumSet是专门为枚举类设计的集合类,EnumSet中的所有元素都必须是制定枚举类型的枚举值。EnumSet集合的元素是有序的
顺序是枚举值在Enum类内定义的顺序。
EnumSet在内部以向量的形式存储,这种存储形式非常紧凑和高效,批量操作执行速度非常快。
EnumSet集合不允许加入null元素。
当试图复制一个Collection集合里的元素来创建EnumSet集合时,必须保证Collection集合里的所有元素都是同一个枚举类的枚举值
8.3.5 各Set实现类的性能分析
HashSet的性能比TreeSet好,因为TreeSet需要额外的红黑树算法来维护集合元素的次序。只有当需要保持排序时才用TreeSet。
插入,删除时HashSet比LinkedHashSet快,因为维护链表带来额外的开销,遍历时LinkedHashSet比HashSet快。
EnumSet是Set中性能最好的,但它只能保存同一枚举类的枚举值作为集合元素。
HashSet,LinkedHashSet,TreeSet,EnumSet都是线程不安全的,通常通过Collections工具类的synchronizedSortedSet方法包装Set


8.4 List
List集合代表一个元素有序、可重复的集合,默认按照元素添加的顺序设置元素的索引,可通过索引访问制定位置的集合元素
List判断两个对象相等的标准是通过equal()方法返回true即可。
List提供了listIterator()方法,该方法返回一个ListIterator对象,ListIterator接口继承Iterator接口,额外提供以下方法
Boolean hasPrevious();Object previous();void add()
8.4.2 ArrayList和Vector实现类
ArrayList和Vector类都是基于数组(Object[])实现的List类,默认长度是10,超过长度时容量自动增加(复制机制)
int newCapacity = (oldCapacity * 3)/2 + 1; 
调整ArrayList和Vector长度的方法:
void ensureCapacity(int minCapacity) 将长度增加到minCapacity
void trimToSize() 将长度调整为当前元素个数
ArrayList是线程不安全的,Vector是线程安全的
LinkedList是基于链表的List实现类,插入删除元素非常快
数组工具类Arrays,该工具类里提供了asList(Object... a)方法,可以把一个数组或指定个数的对象转换成一个List集合
这个集合是Arrays内部类ArrayList的实例。只能遍历,不可增加,删除
8.5 Map
Map的key不允许重复,即Map对象中的任何两个key通过equals方法比较总是返回false
Map的实现类和子接口中key集的存储形式和对应Set集合中元素的存储形式完全相同
keySet()方法返回值是Map中key值的集合;entrySet()的返回值也是返回一个Set集合,此集合的类型为Map.Entry。
Map.Entry是Map声明的一个内部接口,此接口为泛型,定义为Entry<K,V>。它表示Map中的一个实体(一个key-value对)。
接口中有getKey(),getValue方法。
Hashtable是线程安全的,HashMap是线程不安全的,可以使用null做为key或value,但null做为key只能一次
为了成功的在HashMap中放入和取出对象,用作key的对象必须实现hashCode()和equals()方法
HashMap判断两个key相等的标准:equals返回true,hashCode也相等,判断两个value相等的标准:equals返回true
可变对象作为key导致该key不能被准确访问,不能被删除,只能删除没被修改的key所对应的key-value对。
不要用可变对象作为key,尽量不要在程序中修改作为key的可变对象
8.6.2 LinkedHashMap
LinkedHashMap使用双向链表维护key-value对的次序,插入顺序与迭代顺序一致
LinkedHashMap需要维护元素的插入顺序,因此性能略低于HashMap,但迭代有良好的性能
8.6.3 Properties读写属性文件
Properties类是Hashtable类的子类
getProperty(String key) getProperty(String key,String defaultValue)
setProperty(String key,String Value)
load(InputStream in) store(OutputStream out)
8.6.4 StoredMap 和 
Map接口派生出一个SortedMap子接口,SortedMap接口有一个TreeMap实现类。
TreeMap就是一个红黑树数据结构TreeMap存储key-value对时,需要根据key对节点进行排序,保证key-value处于有序状态
两种排序方式:自然排序,定制排序
自然排序:TreeMap 的所有key必须实现Comparable接口,而且所有的key应该是同一类的对象,否则抛出ClassCastException
定制排序:创建TreeMap时,传入一个Comparator对象,该对象负责对TreeMap中所有key进行排序,采用定制排序时不要求map
的key实现Comparable接口
TreeMap类似于TreeSet判断两个元素相等的标准:两个key通过compareTo()方法返回0,则这两个key是相等的。
如果使用自定义类作为TreeMap的key,则重写该类的equals()方法和compareTo()方法时应保持一致的返回结果。
8.6.5 WeakHashMap实现类
WeakHashMap与HashMap的用法基本相似。区别在于HashMap保留了对key的强引用,这意味着HashMap对象不被销毁,
HashMap的所有key所引用的对象就不会被垃圾回收,HashMap也不会自动删除这些key所对应的key-value对。
WeakHashMap的key只保留了对时机对象的弱引用,因此垃圾回收了该key所对应的实际对象后,WeakHashMap会自动
删除该key对应的key-value对
8.6.6 IdentityHashMap实现类
实现机制与HashMap基本相似,但它在处理两个key相等时比较独特,在IdentityHashMap中,当且仅当两个key严格相等(key1==key2)
时,IdentityHashMap才认为两个key相等。
8.6.7 EnumMap
EnumMap中的所有key都必须是单个枚举类的枚举值。
EnumMap内部以数组形式存储
EnumMap根据key的自然排序(即枚举值在枚举类中的定义顺序)来维护key-value对的顺序
EnumMap不允许使用null作为key,但允许null作为value。添加null key 抛空指针异常,查询、删除不会抛出异常
创建EnumMap时必须指定一个枚举类
8.6.8 各Map实现类的性能分析
HashMap和Hashtable的效率大致相同,Hashtable要慢,因为线程同步
TreeMap比hashMap慢,因为key-value是排好序的
LinkedHashMap比HashMap慢一点,因为要维护链表保持Map中的key-value添加顺序
IdentityHashMap性能与HashMap差不多,只是它使用==而不是equals()方法判断元素相等
EnumMap性能最好,但只能用枚举类的枚举值作为key
8.8 操作集合的工具类:Collections(静态类)
Collections提供了对集合排序的操作,查找,排序操作
Collections类中提供了多个synchronizedXxx()方法,该方法可将指定集合包装成线程同步的集合
HashSet,TreeSet,ArrayList,ArrayDeque,LinkedList,HashMap,TreeMap都是线程不安全的
eg:Collection c = Collections.synchronizedCollection(new ArrayList());
List l = Collections.synchronizedList(new ArrayList());
Set s = Collections.synchronizedSet(new HashSet());
Map m = Collections.synchronizedMap(new HashMap());
8.8.4 设置不可变集合
Collections提供如下三类方法返回一个不可变的集合
emptyXxx():返回一个空的、不可变的集合对象
singletonXxx():返回一个只包含指定对象(只有一个或一项元素)的,不可变的集合对象
unmodifiableXxx():返回制定集合对象的不可变视图
以上三类方法的参数是原有集合对象,返回值是该集合的“只读”版本
0 0
原创粉丝点击