您好,欢迎访问一九零五行业门户网

详细介绍Java容器相关知识全面总结(图)

java实用类库提供了一套相当完整的容器来帮助我们解决很多具体问题。因为我本身是一名android开发者,包括我在内很多安卓开发,最拿手的就是listview(recycleview)+baseadapter+arraylist三剑客, 平时接触使用的容器也只有arraylist和hashmap。导致对于整个java容器体系的掌握和使用还停留在很浅的层面。省不足而思改进,那么跟着我来总结一下java容器的相关知识吧。
结构java容器类的继承结构
具体介绍
list
set
queue
迭代器
collection
map
一些建议
进阶·并发容器
copyonwritearraylist与copy-on-write策略
concurrentlinkedqueue
concurrenthashmap与锁分段技术
阻塞队列
java容器类的继承结构java容器类库定义了两个不同概念的容器,collection和map
collection 一个独立元素的序列,这些元素都服从一条或多条规则。list必须按照插入的顺序保存元素。set不能有重复元素。queue按照排队规则来确定对象产生的顺序。
(文中jdk源码版本无特殊说明均为jdk1.8.0_101)
public interface collection<e> extends iterable<e> { int size(); boolean isempty(); boolean contains(object o); iterator<e> iterator(); object[] toarray(); <t> t[] toarray(t[] a); boolean add(e e); boolean remove(object o); boolean containsall(java.util.collection<?> c); boolean addall(java.util.collection<? extends e> c); boolean removeall(java.util.collection<?> c); ... //省略了其他方法 }
可以看到,java定义了collection接口和内部集合的基本操作方法,collection默认可以进行对集合末端添加元素,删除指定元素等操作。list、set、queue接口都继承自collection并定义了各自不同的方法。
map 一组成对的”键值对”对象,允许我们使用键来查找值。
public interface map<k,v> { int size(); boolean containskey(object key); boolean containsvalue(object value); v get(object key); v put(k key, v value); v remove(object key); void putall(java.util.map<? extends k, ? extends v> m); void clear(); set<k> keyset(); collection<v> values(); set<java.util.map.entry<k, v>> entryset(); interface entry<k,v> { k getkey(); v getvalue(); v setvalue(v value); boolean equals(object o); int hashcode(); ... } boolean equals(object o); int hashcode(); }
map内部接口entry<k,v>对应着map的键值对。
具体介绍迭代器先介绍一下迭代器。迭代器本身也是一种设计模式,设计的初衷在于:容器的实现由很多种,而我们想对容器进行遍历操作的话,首先不应该关心容器实现的细节,其次遍历操作应该是轻量级的。迭代器统一了对容器的访问方式,同时创建它的代价很小。值得注意的是,iterator只能单向移动。
public interface iterator<e> { boolean hasnext(); e next(); default void remove() { throw new unsupportedoperationexception("remove"); } default void foreachremaining(consumer<? super e> action) { objects.requirenonnull(action); while (hasnext()) action.accept(next()); } }
通过容器的iterator()方法拿到容器的迭代器
迭代器的next()获取下一个元素
hasnext()判断是否还有元素
remove()删除指定元素
listiteratorlistiterator是iterator的扩展之内,用于各种list类访问,支持双向移动。
collectionlistlist 承诺可以将元素维护在特定的序列中.list接口在collection的基础上添加了大量的方法,使得可以再list中间插入和移除元素。
public interface list<e> extends collection<e> { ... boolean add(e e); boolean remove(object o); boolean containsall(collection<?> c); boolean addall(collection<? extends e> c); boolean addall(int index, collection<? extends e> c); boolean removeall(collection<?> c); boolean retainall(collection<?> c); e get(int index); e set(int index, e element); void add(int index, e element); e remove(int index); int indexof(object o); int lastindexof(object o); java.util.list<e> sublist(int fromindex, int toindex); ... }
有两种类型的list,arraylist和linkedlist
list类型优点缺点底层实现
arraylist 随机访问元素较快 中间元素的插入和删除较慢 数组
linkedlist 中间元素的插入和删除,顺序访问的优化 随机访问元素较慢 双向链表
setset不保存重复的元素,通常用于快速查找元素。值得一提的是,set具有与collection完全一样的接口,没有任何额外的功能。 存入的元素必须定义equals()方法
set类型使用场景底层实现
hashset 快速查找,元素必须定义hashcode() 链表
treeset 保持次序,元素必须实现comparable接口 红-黑树结构
linkedhashset 维护次序的hashset, 元素必须定义hashcode() 链表
queue除了并发应用,queue仅有的两个实现是linkedlist和priorityqueue, 其中linkedlist同时实现了list, deque接口。它们的差异在于排序行为而不是性能。
public interface queue<e> extends collection<e> { boolean add(e e); boolean offer(e e); e remove(); e poll(); e element(); e peek(); }
mapmap类型使用场景底层实现
hashmap 快速查询 散列表
linkedhashmap 迭代遍历具有顺序(插入顺序 or 最近最少使用) 链表
treemap 具有排序,唯一可以返回子树的map(submap()) 红-黑树结构
weakhashmap 弱键映射,映射之外无引用的键,可以被垃圾回收 散列表
concurrenthashmap 线程安全的map 链表
identityhashmap 使用==代替equals()对键进行排序,专位解决特殊问题 链表
我们可以手工调整hashmap来调整性能,涉及到如容量、初始容量、尺寸、负载因子等概念。感兴趣的话可以看一些相关资料。
一些建议不要使用过时的容器 如vector enumeration hashtable stack(没错,这就是java最初的糟糕设计,实际中使用栈的话推荐linkedlist)
进阶·并发容器这里不会讨论的太细致的实现,仅仅简单介绍一下基础知识,感兴趣的可以阅读《java 并发编程的艺术》这本书。
copyonwritearraylist与copy-on-write策略copy-on-write简称cow,是一种用于程序设计中的优化策略。其基本思路是,从一开始大家都在共享同一个内容,当某个人想要修改这个内容的时候,才会真正把内容copy出去形成一个新的内容然后再改,这是一种延时懒惰策略。从jdk1.5开始java并发包里提供了两个使用copyonwrite机制实现的并发容器,它们是copyonwritearraylist和copyonwritearrayset。copyonwrite容器非常有用,可以在非常多的并发场景中使用到。
copyonwrite容器即写时复制的容器。通俗的理解是当我们往一个容器添加元素的时候,不直接往当前容器添加,而是先将当前容器进行copy,复制出一个新的容器,然后新的容器里添加元素,添加完元素之后,再将原容器的引用指向新的容器。这样做的好处是我们可以对copyonwrite容器进行并发的读,而不需要加锁,因为当前容器不会添加任何元素。所以copyonwrite容器也是一种读写分离的思想,读和写不同的容器。
copyonwrite容器只能保证数据的最终一致性,不能保证数据的实时一致性。所以如果你希望写入的的数据,马上能读到,请不要使用copyonwrite容器。
concurrentlinkedqueue在并发编程中,有时候需要使用线程安全的队列或列表。通常实现线程安全有两种方式,一种是使用阻塞算法,一种是使用非阻塞算法。非阻塞算法实现基础为循环cas(compare and swipe 比较和交换)。
concurrentlinkedqueue技术上的实现与copyonwritearraylist与copy类似,但是容器只有部分内容而不是整个容器可以被复制和修改。concurrentlinkedqueue有head节点和tail节点组成,每个节点由节点元素(item)和指向下一个结点(next)的引用组成。节点之间通过next关联起来,形成一张链表结构的队列。
concurrenthashmap与锁分段技术concurrenthashmap是线程安全且高效的hashmap。多线程环境下,使用非线程安全的hashmap会导致死循环,而如文章中建议的那样,hashtable这种过时容器效率低下(使用synchronized来保证线程安全)。concurrenthashmap使用锁分段技术,大大提高了并发使用的效率。
锁分段技术: 假设容器有多把锁,每一把锁用于锁容器其中一部分数据,当多线程访问容器不同数据段数据时,线程间就不存在锁竞争,从而提高并发访问效率。
阻塞队列jdk7 提供了7个阻塞队列,实现原理都是基于生产-消费模式的等待通知机制。
阻塞队列类型特点
arrayblockingqueue 由数组结构组成的有界阻塞队列
linkedblockingqueue 由链表结构组成的有界阻塞队列
priorityblockingqueue 支持优先级排序的无界阻塞队列
delayqueue 使用优先级队列实现的无界阻塞队列
synchronousqueue 不储存元素的阻塞队列
linkedtransferqueue 由链表结构组成的无界阻塞队列
linkedblockingqueue 由链表结构组成的双向阻塞队列
以上就是详细介绍java容器相关知识全面总结(图)的详细内容。
其它类似信息

推荐信息