(6)Java数据结构-- 转: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> implementsCollection<e>, Serializable { finalCollection<e> c; // Backing Collection finalObject mutex; // Object on which to synchronize SynchronizedCollection(Collection<e> c) { if(c==null) thrownew NullPointerException(); this.c = c; mutex = this; } //... publicboolean add(E e) { //操作集合时简单调用原本的ArrayList对象,只是做了同步 synchronized(mutex) {returnc.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; returntrue;}//ArrayList.removepublic E remove(int index) { rangeCheck(index); modCount++; E oldValue = elementData(index); intnumMoved = 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 returnoldValue;}//Vector add方法上多了synchronized关键字publicsynchronized boolean add(E e) { modCount++; ensureCapacityHelper(elementCount + 1); elementData[elementCount++] = e; returntrue;}</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{ //头尾节点 transientNode<e> first; transientNode<e> last;}//节点类 privatestatic classNode<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 ">publicclass HashMap<k,v>extends AbstractMap<k,v>implements Map<k,v>, Cloneable, Serializable{ transientEntry<k,v>[] table; publicV put(K key, V value) { if(key == null) returnputForNullKey(value); inthash = hash(key); inti = 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); returnoldValue; } } addEntry(hash, key, value, i); returnnull; }}staticclass Entry<k,v> implementsMap.Entry<k,v> { finalK key; V value; Entry<k,v> next; inthash;}</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 ">publicclass HashSet<e>extends AbstractSet<e>implements Set<e>, Cloneable, java.io.Serializable{ //无意义对象来作为Map的value privatestatic finalObject PRESENT = newObject(); publicboolean add(E e) { returnmap.put(e, PRESENT)==null; }}</e></e></e></code> |
HashSet、TreeSet分别默认维护一个HashMap、TreeMap。
(6)Java数据结构-- 转:JAVA常用数据结构及原理分析的更多相关文章
- java 中几种常用数据结构
Java中有几种常用的数据结构,主要分为Collection和map两个主要接口(接口只提供方法,并不提供实现),而程序中最终使用的数据结构是继承自这些接口的数据结构类. 一.几个常用类的区别 1.A ...
- Java 集合框架(常用数据结构)
早在Java 2中之前,Java就提供了特设类.比如:向量(Vector).栈(Stack).字典(Dictionary).哈希表(Hashtable)这些类(数据结构)用来存储和操作对象组.虽然这些 ...
- java基础进阶二:HashMap实现原理分析
HashMap实现原理分析 1. HashMap的数据结构 数据结构中有数组和链表来实现对数据的存储,但这两者基本上是两个极端. 数组 数组存储区间是连续的,占用内存严重,故空间复杂的很大.但数组的二 ...
- Java 线程同步组件 CountDownLatch 与 CyclicBarrier 原理分析
1.简介 在分析完AbstractQueuedSynchronizer(以下简称 AQS)和ReentrantLock的原理后,本文将分析 java.util.concurrent 包下的两个线程同步 ...
- 【Java编程实战】Metasploit_Java后门运行原理分析以及实现源码级免杀与JRE精简化
QQ:3496925334 文章作者:MG1937 CNBLOG博客ID:ALDYS4 未经许可,禁止转载 某日午睡,迷迷糊糊梦到Metasploit里有个Java平台的远控载荷,梦醒后,打开虚拟机, ...
- 【Java线程安全】 — 常用数据结构及原理(未完结)
本文主要记录自己对于多线程安全的学习,先来记几个线程安全模型. 首先最重要的当然是volatile和AQS了: 我们知道,整个java.cuncurrent包的核心就是volatile,CAS加自旋悲 ...
- 数据结构与算法——常用数据结构及其Java实现
前言 仿佛一下子,2017年就快过去一半了,研一马上就要成为过去式了,我打算抓住研一的尾巴,好好梳理一下数据结构与算法,毕竟这些基础知识是很重要的嘛.所以准备在这里搞一个系列的文章,以期透彻. 本系列 ...
- 【Java并发编程】1、ConcurrentHashMap原理分析
集合是编程中最常用的数据结构.而谈到并发,几乎总是离不开集合这类高级数据结构的支持.比如两个线程需要同时访问一个中间临界区(Queue),比如常会用缓存作为外部文件的副本(HashMap).这篇文章主 ...
- Java JDK 动态代理使用及实现原理分析
转载:http://blog.csdn.net/jiankunking 一.什么是代理? 代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问.代理类负责为委托类预处理 ...
- 【Java并发编程】23、ConcurrentHashMap原理分析(1.7和1.8版本对比)
jdk 1.8版本 ConcurrentHashMap在1.8中的实现,相比于1.7的版本基本上全部都变掉了.首先,取消了Segment分段锁的数据结构,取而代之的是数组+链表(红黑树)的结构.而对于 ...
随机推荐
- 解决jQuery ajax动态新增节点无法触发点击事件的问题
在写ajax加载数据的时候发现,后面添加进来的demo节点元素,失去了之前的点击事件.为什么点击事件失效,我们该怎么去解决呢? 其实最简单的方法就是直接在标签中写onclick="" ...
- Lucene的其他搜索(三)
生成索引: package com.wp.search; import java.nio.file.Paths; import org.apache.lucene.analysis.Analyzer; ...
- qml: QtCharts模块的使用(基本配置)------<一>
QtCharts模块可以用于绘制图表: 导入模块: import QtCharts 2.2 例子: import QtQuick 2.0 import QtCharts 2.2 ChartView { ...
- 【优秀的艺术文字和图标设计软件】Art Text 3.2.3 for Mac
[简介] Art Text 3.2.3 版本,这是一款Mac上简单易用的艺术文字和图标设计软件,今这款软件内置了大量的背景纹理和特效,能够让我们非常快速的制作出漂亮的图标,相比专业的PS,Art ...
- 2017-12-14python全栈9期第一天第一节之太白自我介绍和内容大纲
1.计算机基础 2.python历史 3.python的环境 4.Python的发展 5.python的种类 6.变量 7.常量 8.注释 9.用户交互 10.基础类型初始 11.if 12.whil ...
- diff补丁格式
title: diff补丁格式 tags: 学习 categories: 学习 date: 2018-09-20 21:03:53 --- diff补丁格式 在Uboot学习中,接触到了打补丁这个操作 ...
- MySQL 8.0.14 新的密码认证方式和客户端链接
MySQL 8.0.14 新的密码认证方式和客户端链接 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. MySQL8.0在密码认证方式发生了改变,这也是有点小伙伴在MySQL创建 ...
- java类的加载和执行顺序
以前面试总会碰到涉及到类的执行过程的笔试题.下面记录我自己的测试结果: public class ClassA { public static ClassA classa = new ClassA() ...
- 【JS】JavaScript中Null和undefind区别
1.undefined:只有一个值,及特殊的undefined.在使用var声明变量但未对其初始化时,这个变量的值是undefined,简言之,undefined就是表示变量申明了但未初始化时的值. ...
- 01--STL泛型编程了解
开始学习侯捷老师的课程了~~ 一:六大组件关系 容器(Container) 算法(Algorithm) 迭代器(Iterator) 仿函数(Function object) 适配器(Adaptor) ...