JAVA常用数据结构及原理分析
JAVA常用数据结构及原理分析
http://www.2cto.com/kf/201506/412305.html
前不久面试官让我说一下怎么理解java数据结构框架,之前也看过部分源码,balabala讲了一堆,现在总结一下。
java.util包中三个重要的接口及特点:List(列表)、Set(保证集合中元素唯一)、Map(维护多个key-value键值对,保证key唯一)。其不同子类的实现各有差异,如是否同步(线程安全)、是否有序。
常用类继承树:
以下结合源码讲解常用类实现原理及相互之间的差异。
Collection (所有集合类的接口)
List、Set都继承自Collection接口,查看JDK API,操作集合常用的方法大部分在该接口中定义了。
Collections (操作集合的工具类)
对于集合类的操作不得不提到工具类Collections,它提供了许多方便的方法,如求两个集合的差集、并集、拷贝、排序等等。
由于大部分的集合接口实现类都是不同步的,可以使用Collections.synchronized*方法创建同步的集合类对象。
如创建一个同步的List:List synList = Collections.synchronizedList(new ArrayList());
其实现原理就是重新封装new出来的对象,操作对象时用关键字synchronized同步。看源码很容易理解。
Collections部分源码:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
<code class="language-java hljs ">//Collections.synchronizedList返回的是静态类SynchronizedCollection的实例,最终将new出来的ArrayList对象赋值给了Collection<e> c。static class SynchronizedCollection<e> implements Collection<e>, Serializable { final Collection<e> c; // Backing Collection final Object mutex; // Object on which to synchronize SynchronizedCollection(Collection<e> c) { if (c==null) throw new NullPointerException(); this.c = c; mutex = this; } //... public boolean add(E e) { //操作集合时简单调用原本的ArrayList对象,只是做了同步 synchronized (mutex) {return c.add(e);} } //...}</e></e></e></e></e></code> |
List (列表)
ArrayList、Vector是线性表,使用Object数组作为容器去存储数据的,添加了很多方法维护这个数组,使其容量可以动态增长,极大地提升了开发效率。它们明显的区别是ArrayList是非同步的,Vector是同步的。不用考虑多线程时应使用ArrayList来提升效率。
ArrayList、Vector 部分源码:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
<code class="language-java hljs ">//ArrayList.addpublic boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!! //可以看出添加的对象放到elementData数组中去了 elementData[size++] = e; return true;}//ArrayList.removepublic E remove(int index) { rangeCheck(index); modCount++; E oldValue = elementData(index); int numMoved = size - index - 1; if (numMoved > 0) //移除元素时数组产生的空位由System.arraycopy方法将其后的所有元素往前移一位,System.arraycopy调用虚拟机提供的本地方法来提升效率 System.arraycopy(elementData, index+1, elementData, index, numMoved); elementData[--size] = null; // Let gc do its work return oldValue;}//Vector add方法上多了synchronized关键字public synchronized boolean add(E e) { modCount++; ensureCapacityHelper(elementCount + 1); elementData[elementCount++] = e; return true;}</code> |
LinkedList是链表,略懂数据结构就知道其实现原理了。链表随机位置插入、删除数据时比线性表快,遍历比线性表慢。
双向链表原理图:
LinkedList部分源码:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
<code class="language-java hljs ">//源码很清晰地表达了原理图public class LinkedList<e>extends AbstractSequentialList<e>implements List<e>, Deque<e>, Cloneable, java.io.Serializable{ //头尾节点 transient Node<e> first; transient Node<e> last;}//节点类 private static class Node<e> { //节点存储的数据 E item; Node<e> next; Node<e> prev; Node(Node<e> prev, E element, Node<e> next) { this.item = element; this.next = next; this.prev = prev; }}</e></e></e></e></e></e></e></e></e></e></e></code> |
由此可根据实际情况来选择使用ArrayList(非同步、非频繁删除时选择)、Vector(需同步时选择)、LinkedList(频繁在任意位置插入、删除时选择)。
Map(存储键值对,key唯一)
HashMap结构的实现原理是将put进来的key-value封装成一个Entry对象存储到一个Entry数组中,位置(数组下标)由key的哈希值与数组长度计算而来。如果数组当前下标已有值,则将数组当前下标的值指向新添加的Entry对象。
有点晕,看图吧:
看完图再看源码,非常清晰,都不需要注释。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
<code class="language-java hljs ">public class HashMap<k,v>extends AbstractMap<k,v>implements Map<k,v>, Cloneable, Serializable{ transient Entry<k,v>[] table; public V put(K key, V value) { if (key == null) return putForNullKey(value); int hash = hash(key); int i = indexFor(hash, table.length); //遍历当前下标的Entry对象链,如果key已存在则替换 for (Entry<k,v> e = table[i]; e != null; e = e.next) { Object k; if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { V oldValue = e.value; e.value = value; e.recordAccess(this); return oldValue; } } addEntry(hash, key, value, i); return null; }}static class Entry<k,v> implements Map.Entry<k,v> { final K key; V value; Entry<k,v> next; int hash;}</k,v></k,v></k,v></k,v></k,v></k,v></k,v></k,v></code> |
TreeMap是由Entry对象为节点组成的一颗红黑树,put到TreeMap的数据默认按key的自然顺序排序,new TreeMap时传入Comparator自定义排序。红黑树网上很多资料,我讲不清,这里就不介绍了。
Set(保证容器内元素唯一性)
之所以先讲Map是因为Set结构其实就是维护一个Map来存储数据的,利用Map结构key值唯一性。
HashSet部分源码:
|
1
2
3
4
5
6
7
8
9
10
11
|
<code class="language-java hljs ">public class HashSet<e>extends AbstractSet<e>implements Set<e>, Cloneable, java.io.Serializable{ //无意义对象来作为Map的value private static final Object PRESENT = new Object(); public boolean add(E e) { return map.put(e, PRESENT)==null; }}</e></e></e></code> |
HashSet、TreeSet分别默认维护一个HashMap、TreeMap。
JAVA常用数据结构及原理分析的更多相关文章
- (6)Java数据结构-- 转:JAVA常用数据结构及原理分析
JAVA常用数据结构及原理分析 http://www.2cto.com/kf/201506/412305.html 前不久面试官让我说一下怎么理解java数据结构框架,之前也看过部分源码,balab ...
- Java 常用数据结构对象的实现原理 集合类 List Set Map 哪些线程安全 (美团面试题目)
Java中的集合包括三大类,它们是Set.List和Map, 它们都处于java.util包中,Set.List和Map都是接口,它们有各自的实现类. List.Set都继承自Collection接口 ...
- 原子类java.util.concurrent.atomic.*原理分析
原子类java.util.concurrent.atomic.*原理分析 在并发编程下,原子操作类的应用可以说是无处不在的.为解决线程安全的读写提供了很大的便利. 原子类保证原子的两个关键的点就是:可 ...
- Java NIO使用及原理分析 (四)
在上一篇文章中介绍了关于缓冲区的一些细节内容,现在终于可以进入NIO中最有意思的部分非阻塞I/O.通常在进行同步I/O操作时,如果读取数据,代码会阻塞直至有 可供读取的数据.同样,写入调用将会阻塞直至 ...
- Java NIO使用及原理分析 (四)(转)
在上一篇文章中介绍了关于缓冲区的一些细节内容,现在终于可以进入NIO中最有意思的部分非阻塞I/O.通常在进行同步I/O操作时,如果读取数据,代码会阻塞直至有 可供读取的数据.同样,写入调用将会阻塞直至 ...
- 【转载】图解Java常用数据结构(一)
图解Java常用数据结构(一) 作者:大道方圆 原文:https://www.cnblogs.com/xdecode/p/9321848.html 最近在整理数据结构方面的知识, 系统化看了下Jav ...
- Java NIO使用及原理分析 (一)(转)
最近由于工作关系要做一些Java方面的开发,其中最重要的一块就是Java NIO(New I/O),尽管很早以前了解过一些,但并没有认真去看过它的实现原理,也没有机会在工作中使用,这次也好重新研究一下 ...
- Java NIO使用及原理分析(1-4)(转)
转载的原文章也找不到!从以下博客中找到http://blog.csdn.net/wuxianglong/article/details/6604817 转载自:李会军•宁静致远 最近由于工作关系要做一 ...
- Java NIO使用及原理分析(二)
在第一篇中,我们介绍了NIO中的两个核心对象:缓冲区和通道,在谈到缓冲区时,我们说缓冲区对象本质上是一个数组,但它其实是一个特殊的数组,缓冲区对象内置了一些机制,能够跟踪和记录缓冲区的状态变化情况,如 ...
随机推荐
- RMAN备份演练进阶篇
前篇介绍了通过rman进行各种备份,进阶篇则主要是rman的一些功能扩展和增加功能,利用前篇你已经完全可以完成数据库的备份,而通过本篇你可以更好更方便的完成数据库的备份. 一.建立增量备份 如果数据库 ...
- 夺命雷公狗---DEDECMS----16dedecms取出首页今日更新
我们这次就要来取出我们的电影和电视剧以及综艺节目: 我们首先在我们受页面的模版文件中获取电影和电视剧的标签: 我们发现这里有一大堆,我只留一个即可: 然后我们到后台更新下首页的模版,看下是否只有一个模 ...
- 搞不定linux下的无线网卡驱动的权宜之计
毕竟windows用了这么些年了,对windows下的一些东西也比较熟悉,还有就是windows的软件方式比较傻瓜. 在linux下搞不定无线网卡啊,幸亏有甲骨文的virtualbox,咱虚拟一个xp ...
- 锋利的JQuery(三)
事件冒泡: 解决方式: 1.使用事件对象:$("element").bind("click",function(event){}); 这个事件对象只有事件处理函 ...
- 查看innodb表空间
使用脚本innodb_space,关于innodb的页管理方式可以参考Jeremy Cole的innodb的页管理方式, innodb_space -f test/t.ibd space-page-t ...
- Thinkphp用exp表达式执行mysql语句,查询某字段不为空is not null,自动增值
Thinkphp用exp表达式执行mysql语句,查询某字段不为空is not null,自动增值 Thinkphp 的文档经常不够完整的表达MYSQL的各种组合,is not null在thinkp ...
- Mac下使用Automator实现截屏编辑保存
以前在Windows下使用百度或者搜狗输入法的截图工具很方便.❶快捷键(Alt+X,我设置的是这个),❷选择区域,❸编辑所选区域,包括添加文字,线条框框,调色,❹点击『✔️』选择保存位置,修改文件名保 ...
- Hosting custom WPF calendar control in AX 2012
原作者: https://community.dynamics.com/ax/b/axilicious/archive/2013/05/20/hosting-custom-wpf-calendar-c ...
- svn搭建以及可能遇到的问题解决方案
Svn服务器的安装和配置 1.安装svn服务器端软件从镜像服务器或者YUM源下载安装SVN服务器软件:yum install subversion mkdir /usr/local/svn //创建S ...
- 26、Oracle(二)
1)掌握多行函数与分组操作 2)掌握多表查询与子查询 3)理解集合查询与掌握Oracle分页语法 4)理解创建.修改和删除表和表约束 --------------------------------- ...