Java基础容器
Posted 流动的城市
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java基础容器相关的知识,希望对你有一定的参考价值。
Java Collections框架
该框架包含了集合接口以及这些接口的实现类,还有操作这些接口的算法或者工具类。其中List Set Queue Stack和Map都继承自Collection接口,Collection是整个集合框架的基础。
1. Set:表示数学意义上的集合,不允许元素是重复的,因此在存入Set中的对象必须实现equals保证对象的唯一性。其实现类有HashSet和TreeSet,其中TreeSet实现了SortedSet接口,因此是有序的。
2. List:被看做是有序的Collection。按对象进入顺序保存,所以可以对元素的插入和删除位置进行精确的控制。实现类是LinkedList ArrayList 和Vector
3. Map:提供了一个从键到值得映射的数据结构,用于保存键值对。其中的值是可以重复的,但是键是唯一的,不可重复。实现类: HashMap TreeMap LinkedHashMap WeakHashMap等。其中HashMap是基于散列表实现的,因此可以通过对象的hashCode进行快速查询,LinkedHashMap是通过列表维护的,TreeMap是基于红黑树实现的。
迭代器与ConcurrentModificationException
迭代器也是一个对象,其功能是遍历并选择序列中的对象,提供了一种访问容器中的数据但是又不需要暴露容器内部实现的方式。使用容器的iterator()方法就可以返回一个迭代器对象,然后通过其next()就可以遍历,remove()删除,hasNext()判断是否还有元素。
ConcurrentModificationException是在使用迭代器进行遍历容器的时候继续修改容器内容,大多数会出现在多线程的场景中。在调用iterator()获取迭代器的时候,同时会获取该迭代器所遍历集合中对象的个数,每次调用next()的时候需判断当前个数和获取迭代器时得到的个数是否相等,如果不相等,就会抛出这个异常。所以在对容器进行遍历的时候,无论是单线程还是多线程,如果存在对容器的修改,那么可以采用的方法是将需要增删的对象存入其他集合中,待遍历完成之后进行批量操作。
多线程情况下避免ConcurrentModificationException:
1. 使用线程安全的容器,比如ConcurrentHashMap和CopyOnWriteArrayList等
2. 使用同步代码块,保证并发安全性,但是仅仅对于并发度比较小的情形下有效,并发度高的时候效率低
ArrayList Vector LinkedList
三者都是长度可变数组,其中ArrayList Vector都是基于存储元素的Object[] array来实现的,在内存中存放是连续的,因此支持随机访问。其中扩容的时候ArrayList扩大为原来的1.5倍,而Vector扩大为原来的2倍。两者的区别是线程安全性,ArrayList不是线程安全的,Vector由于增删操作都是直接或者间接同步的,所以是线程安全的。
LinkedList是采用双向链表实现,所以不支持随机访问,但是插入效率比较高。同时,该容器不是线程安全的。
HashMap HashTable TreeMap WeakHashMap
HashMap和HashTable的区别:
1. HashMap是HashTable的轻量级实现(非线程安全的实现),都实现了Map接口,但是HashMap允许空的键和空的值
2. HashMap由于含有空的键,因此把HashTable的contains()方法去掉了,而增加了containsKey containsValue
3. HashTable是线程安全的,而HashMap不是,因此HashMap的效率高一点
4. HashTable默认大小是11,增加方式是2*old + 1而HashMap中默认大小是16,扩容时保证是2的指数
TreeMap由于实现了SortMap接口,所以对于保存的记录是按键值有序的。LinkedHashMap是HashMap的实现子类,可以实现输出顺序和输入顺序相同。
WeakHashMap和HashMap类似,只是WeakHashMap中的key采用的是弱引用,也就是说如果WeakHashMap中的键不被外界引用,那么就可以被垃圾搜集器搜集掉。
自定义类型作为HashMap或者HashTable的key需要注意的问题
两个容器对于存放其中的对象都有一个最基本的要求就是不能存放重复的key。也就是每一个key只能唯一的映射一个value,当出现重复的key的时候不会新建一对映射。
因此在使用自定义类型作为key的时候需要注意:
1. 如果需要根据对象的某些属性定义对象的相等关系,那么就需要重写equals方法,而重写了equals方法就必须重写hashCode方法
2. 自定义类作为HashMap或者HashTable的key的时候,最好把类设计为不可变类
3. 如果两个对象相等,那么这两个对象的hashCode是一样的,反之未必。从HashMap或者HashTable的查询和插入过程可以清晰的看出
HashMap插入键值对:
1. 调用key的hashCode方法获取hash值h1,如果h1在HashMap中不存在,那么直接创建键值对
2. 如果h1在HashMap中已经存在,那么通过equals方法,判断所有h1对应的对象是否返回true,如果返回false,那么说明新的key是不存在的,建立键值对,加入
3. 如果equals返回的是true,那么key是已经存在的,将新的value值覆盖旧值
出现2中的情况(hash相同,但是对象不等),说明出现了冲突,冲突处理方式有多种,数据结构中将hash的时候提到过,比如:开放地址法,链地址法,再hash法
HashMap中查找一个value:
通过key的hashCode方法获取key的hash值h1,如果h1对一个的key值有多个,那么就遍历这些hash为h1的key,通过equals方法进行对比,只有equals方法返回为true的时候就找到了。
以上是关于Java基础容器的主要内容,如果未能解决你的问题,请参考以下文章