首页 技术 正文
技术 2022年11月23日
0 收藏 494 点赞 5,103 浏览 4457 个字

java中容器类数据结构主要在java.util包中。

java.util包中三个重要的接口及特点:List(列表)、Set(保证集合中元素唯一)、Map(维护多个key-value键值对,保证key唯一)。其不同子类的实现各有差异,如是否同步(线程安全)、是否有序。
常用类继承树:
java常见数据结构整理

以下结合源码讲解常用类实现原理及相互之间的差异。

Collection (所有集合类的接口)
List、Set都继承自Collection接口,查看JDK API,操作集合常用的方法大部分在该接口中定义了。
java常见数据结构整理

Collections (操作集合的工具类)
对于集合类的操作不得不提到工具类Collections,它提供了许多方便的方法,如求两个集合的差集、并集、拷贝、排序等等。
由于大部分的集合接口实现类都是不同步的,可以使用Collections.synchronized*方法创建同步的集合类对象。
如创建一个同步的List:
List synList = Collections.synchronizedList(new ArrayList());
其实现原理就是重新封装new出来的对象,操作对象时用关键字synchronized同步。看源码很容易理解。
Collections部分源码:

?

12345678910111213141516171819 <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 部分源码:

?

12345678910111213141516171819202122232425262728293031 <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是链表,略懂数据结构就知道其实现原理了。链表随机位置插入、删除数据时比线性表快,遍历比线性表慢。
双向链表原理图:
java常见数据结构整理
LinkedList部分源码:

?

123456789101112131415161718192021 <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对象。
有点晕,看图吧:
java常见数据结构整理

完图再看源码,非常清晰,都不需要注释。

?

123456789101112131415161718192021222324252627282930 <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部分源码:

?

1234567891011 <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。

相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:8,933
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,454
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,267
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,084
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:7,716
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:4,753