java数据结构原理_JAVA常用数据结构及原理分析

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

常用类继承树:

3ab6fc574fffef86d80dcb6baeee4b59.png

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

Collection (所有集合类的接口)

List、Set都继承自Collection接口,查看JDK API,操作集合常用的方法大部分在该接口中定义了。

f4453aa6bcf4947e6fdd3a0e08ab1002.png

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

//Collections.synchronizedList返回的是静态类SynchronizedCollection的实例,最终将new出来的ArrayList对象赋值给了Collection

c。

static class SynchronizedCollectionimplements

Collection, Serializable {

final

Collection c;// Backing Collection

final

Object mutex;// Object on which to synchronize

SynchronizedCollection(Collection c) {

if

(c==null)

throw

new NullPointerException();

this.c = c;

mutex =this;

}

//...

public

boolean add(E e) {

//操作集合时简单调用原本的ArrayList对象,只是做了同步

synchronized

(mutex) {return

c.add(e);}

}

//...

}

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

//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;

}

LinkedList是链表,略懂数据结构就知道其实现原理了。链表随机位置插入、删除数据时比线性表快,遍历比线性表慢。

双向链表原理图:

102f9928c1d98402a394b0a18c928cdb.png

LinkedList部分源码:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

//源码很清晰地表达了原理图

public class LinkedList

extends AbstractSequentialList

implements

List, Deque, Cloneable, java.io.Serializable

{

//头尾节点

transient

Node first;

transient

Node last;

}

//节点类

private

static class Node {

//节点存储的数据

E item;

Node next;

Node prev;

Node(Node prev, E element, Node next) {

this.item = element;

this.next = next;

this.prev = prev;

}

}

由此可根据实际情况来选择使用ArrayList(非同步、非频繁删除时选择)、Vector(需同步时选择)、LinkedList(频繁在任意位置插入、删除时选择)。

Map(存储键值对,key唯一)

HashMap结构的实现原理是将put进来的key-value封装成一个Entry对象存储到一个Entry数组中,位置(数组下标)由key的哈希值与数组长度计算而来。如果数组当前下标已有值,则将数组当前下标的值指向新添加的Entry对象。

有点晕,看图吧:

f816fd03b282f28b47d2d66c09d1d654.png

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

?

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

public

class HashMap

extends AbstractMap

implements

Map, Cloneable, Serializable

{

transient

Entry[] 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 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 Entryimplements

Map.Entry {

final

K key;

V value;

Entry next;

int

hash;

}

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

public

class HashSet

extends AbstractSet

implements

Set, Cloneable, java.io.Serializable

{

//无意义对象来作为Map的value

private

static final Object PRESENT =new Object();

public

boolean add(E e) {

return

map.put(e, PRESENT)==null;

}

}

HashSet、TreeSet分别默认维护一个HashMap、TreeMap。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值