集合概述
java集合就像一种容器,我们可以把多个对象丢进该容器中。在编程时,我们需要存放多个数据,当然我们可以使用数组来保存多个对象,但是数组的长度不可变化,且无法保存具有映射关系的数据。集合类主要负责保存,盛装其他数据,因此集合类也被成为容器类。
集合类和数组不一样,数组即可以保存基本类型,也可也保存对象;而集合里保存的只能是对象。java的集合类主要由两个接口派生而出:Collection和Map。
Map
Map用于保存具有映射关系的数据,Map中保存两组值,一组为Key一组为Value,Key与Value都可以是任何引用类型的数据。Map的Key不允许重复,Map 的两个Key使用equals方法判断。
Key与Value之间存在单向一对一的关系,通过指定的key能找到唯一的确定的value值。
如上图所示Map的key放在一起看起就是一个Set集合,而Map也拥有一个keySet()方法用于返回Map里所有key值的Set集合。Map的key与Set里的元素存储形式也很像,虽然Map里存储的是key-value键值对,我么你可以把value当做是key的附属,这样就可以像对待Set一样对待Map。Map提供了一个Entry内部类来封装key-value对,而计算Entry时只考虑Entry封装的key值。
另一方面,将所有的value值放在一起看,又类似一个List,元素之间可以重复并根据索引来查找。所以Map也被称为字典。
HashMap与Hashtable
HashMap与Hashtable都是Map的实现类,他们的关系类似于ArraryList与Vector。而两者之间的关系在各种面试笔试中经常被考到。
- Hashtable是一个古老的Map实现类,线程安全,但是HashMap是线程不安全的,所以为了保证线程安全HashMap需要消耗部分性能维护线程安全,所以Hashtable的性能会比HashMap稍微差一点。
- Hashtable不允许null最为key或者value,否则会跑出NullPointerException异常;但是HashMap可以。
Tips1:Hashtable趣闻,它的命名没有遵守Java的命名规范,但是后来由于使用的人多了,再也不能改为HashTable,所以就沿用了这个名称。
为了成功的在HashMap与Hashtable中存取元素,用做key的对象必须实现hashcode()与equals()方法,判断两个key值相等的条件为:equals方法返回true且hashcode值相等。HashMap与Hashtable判断value相等是通过两个value对象的equals方法。HashMap与Hashtable并不能保证其中key-value键值对的顺序。
与HashSet类似,尽量不要使用可变的对象作为HashMap与Hashtable的key值。
LinkedHashMap
LinkedHashMap使用双向链表维护key-value键值对的次序,该链表维护Map的迭代顺序,迭代顺序与key-value键值对插入的顺序保持一致。
LinkedHashMap需要维护元素的插入顺序,因此性能要略低于HashMap的性能,但在进行迭代访问的时候会有较好的性能。
Properties
Properties是Hashtable的子类,该对象在处理配置文件时把文件的值写入key-value键值对中。
Properties properties = new Properties();
properties.setProperty(key, value);
properties.store(new FileOutputStream("xxxx"), comments);
properties.getProperty(key);
properties.load(new FileInputStream(file));
SortedMap与Treemap
Map接口也派生了一个SortedMap子接口,SortedMap接口也有一个TreeMap类。TreeMap是一个红黑树的数据结构,每个key-value键值对作为红黑树的一个节点并根据key值对Key-value进行排序。同Set一样,也有两种排序方式,详见collection中的TreeSet。
Tips2:Java源码就是先实现了Map再通过包装一个所有value都为null的Map集合实现了Set集合。
WeakHashMap
WeakHashMap与HashMap的使用方法类似,与HashMap的区别在于HashMap的key保留了对实际对象的强引用,这意味这只要HashMap对象不被销毁,该HashMap的所有Key值引用不会被垃圾回收,HashMap也不会自动删除这些key所对应的key-value,但WeakHashMap只保留了对象的弱引用,这意味着如果WeakHashMap的key值如果没有被其他强对象引用,那么这些key值就可能被垃圾回收。
IdentityHashMap
IdentityHashMap是一个特殊的Map实现,当且仅当两个key严格相等(key1=key2)时,IdentityHashMap才认为连个key值相等。IdentityHashMap不能保证key-value对之间的顺序,它与HashMap类似。
EnumMap
EnumMap是一个与枚举类型一起使用的Map。EnumMap不允许使用null作为key,但是可以使用null作为value,会根据枚举值进行自然排序。
各Map实现类的性能分析
- HashMap与Hashtable的性能大致相同,但HashMap比Hashtable稍微快一点。
- TreeMap比HashMap与Hashtable要慢,尤其在插入和删除的时候,但是它的key-value总是处于有序状态。
- 对于一般的应用场景,优先考虑使用HashMap,HashMap是为快速查询设计的
- LinkedHashMap比HashMap慢一点,因为它要维护key-value 的添加顺序。
Tips3:TreeMap的另一种查询技巧,在TreeMap被填充值后,就可以调用keySet()方法,使用toArrary()方法生成key的数组,接下来使用Arrarys的binarySearch()方法在已经排序的数组中快速查找对象。
HashMap与HashSet的性能
对于HashSet,采用hash算法决定在集合中元素的存储位置并通过hash算法来控制集合的大小;对于HashMap,采用hash算法来决定Map中key的存储,并通过hash算法来增加key的大小。
在hash算法中有一个负载极限的概念,决定了hash表的最大填满度,当负载因子达到负载极限时,hash表会自动的成倍增加,并将原有的对象重新分配,这个过程成为refreshing。
HashSet与HashMap的负载极限都时0.75,如果开始就知道HashSet与HashMap会保存很多记录,则可以在开始时就初始化较大的容量,就不会发生refreshing。并且可以高效的增加记录。