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.add
public boolean add(E e) {
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    //可以看出添加的对象放到elementData数组中去了
    elementData[size++] = e;
    return
true;
}
//ArrayList.remove
public 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。

(6)Java数据结构-- 转:JAVA常用数据结构及原理分析的更多相关文章

  1. java 中几种常用数据结构

    Java中有几种常用的数据结构,主要分为Collection和map两个主要接口(接口只提供方法,并不提供实现),而程序中最终使用的数据结构是继承自这些接口的数据结构类. 一.几个常用类的区别 1.A ...

  2. Java 集合框架(常用数据结构)

    早在Java 2中之前,Java就提供了特设类.比如:向量(Vector).栈(Stack).字典(Dictionary).哈希表(Hashtable)这些类(数据结构)用来存储和操作对象组.虽然这些 ...

  3. java基础进阶二:HashMap实现原理分析

    HashMap实现原理分析 1. HashMap的数据结构 数据结构中有数组和链表来实现对数据的存储,但这两者基本上是两个极端. 数组 数组存储区间是连续的,占用内存严重,故空间复杂的很大.但数组的二 ...

  4. Java 线程同步组件 CountDownLatch 与 CyclicBarrier 原理分析

    1.简介 在分析完AbstractQueuedSynchronizer(以下简称 AQS)和ReentrantLock的原理后,本文将分析 java.util.concurrent 包下的两个线程同步 ...

  5. 【Java编程实战】Metasploit_Java后门运行原理分析以及实现源码级免杀与JRE精简化

    QQ:3496925334 文章作者:MG1937 CNBLOG博客ID:ALDYS4 未经许可,禁止转载 某日午睡,迷迷糊糊梦到Metasploit里有个Java平台的远控载荷,梦醒后,打开虚拟机, ...

  6. 【Java线程安全】 — 常用数据结构及原理(未完结)

    本文主要记录自己对于多线程安全的学习,先来记几个线程安全模型. 首先最重要的当然是volatile和AQS了: 我们知道,整个java.cuncurrent包的核心就是volatile,CAS加自旋悲 ...

  7. 数据结构与算法——常用数据结构及其Java实现

    前言 仿佛一下子,2017年就快过去一半了,研一马上就要成为过去式了,我打算抓住研一的尾巴,好好梳理一下数据结构与算法,毕竟这些基础知识是很重要的嘛.所以准备在这里搞一个系列的文章,以期透彻. 本系列 ...

  8. 【Java并发编程】1、ConcurrentHashMap原理分析

    集合是编程中最常用的数据结构.而谈到并发,几乎总是离不开集合这类高级数据结构的支持.比如两个线程需要同时访问一个中间临界区(Queue),比如常会用缓存作为外部文件的副本(HashMap).这篇文章主 ...

  9. Java JDK 动态代理使用及实现原理分析

    转载:http://blog.csdn.net/jiankunking   一.什么是代理? 代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问.代理类负责为委托类预处理 ...

  10. 【Java并发编程】23、ConcurrentHashMap原理分析(1.7和1.8版本对比)

    jdk 1.8版本 ConcurrentHashMap在1.8中的实现,相比于1.7的版本基本上全部都变掉了.首先,取消了Segment分段锁的数据结构,取而代之的是数组+链表(红黑树)的结构.而对于 ...

随机推荐

  1. 第八节,配置分布式TensorFlow

    由于随着神经网络层数的增多,需要训练的参数也会增多,随之而来需要的数据集就会很大,这样会造成需要更大的运算资源,而且还要消耗很长的运算时间.TensorFlow提供了一个可以分布式部署的模式,将一个训 ...

  2. request 对于cookie,session, json的处理

    一.cookie是存放在客户端,session是存放在服务端. 因为http是无状态的,当客户端发送请求给服务端的时候,服务端为了区分下一次发送请求的是不是同一个客户,那么就需要用一种方式记录下这个客 ...

  3. Vuex异步请求数据通过computed计算属性值

    问题描述: 使用Vuex管理数据时,在组件内使用$emit分发事件后,获取回来的数据要自动更新到该组件内,需要使用computed来计算更新. 一开始尝试使用赋值给data的方法,后来发现重新发起aj ...

  4. Jquery Mobile基本元素

    移动端框架 安装: CDN: <link rel="stylesheet" href="http://code.jquery.com/mobile/1.3.2/jq ...

  5. SQL Server日志过大,清理日志

    直接执行下面的代码 USE [master] GO ALTER DATABASE 数据库 SET RECOVERY SIMPLE WITH NO_WAIT GO ALTER DATABASE 数据库 ...

  6. JAVA核心技术I---JAVA基础知识(查漏补缺private,static)

    一:private对于类和对象(同C++) private是只有这个类内部可以访问(类的成员函数和定义初始化) private是类之间的限制,而不是对对象的限制<重点> 同类对象是可以直接 ...

  7. python 存储引擎 mysql(库,表, 行) 单表多表操作 (foreign key) sql_mode pymysql模块讲解

    ##################总结############### mysql 常用数据类型 整型:tinyint  int(42亿条左右)  bigint 小数:float double dec ...

  8. Nginx 简单安装

    关于nginx的介绍:http://baike.baidu.com/link?url=UZjpP8y4MUgrjqACfxd7c3Cm4L8PnJsKkxSJQ3CrRcKZUjkkl4zGNs6Pr ...

  9. 搭建vscode+vue环境

    转自:https://blog.csdn.net/mao834099514/article/details/79138484 一.安装vue.js 1.简介 Vue.js(读音 /vjuː/, 类似于 ...

  10. Golang入门教程(十三)延迟函数defer详解

    前言 大家都知道go语言的defer功能很强大,对于资源管理非常方便,但是如果没用好,也会有陷阱哦.Go 语言中延迟函数 defer 充当着 try...catch 的重任,使用起来也非常简便,然而在 ...