方舟开发框架容器类 API 的介绍与使用

2022-03-07 00:00:00 操作 元素 容器 扩容 容量

作者:liuxin,华为工程师

容器类,顾名思义就是存储的类,用于存储各种数据类型的元素,并具备一系列处理数据元素的方法。在方舟开发框架中,容器类采用了类似静态的语言来实现,并通过NAPI框架对外提供。通过对存储位置以及属性的限制,让每种类型的数据都能在完成自身功能的基础上剪除冗余分支,保证了数据的高效访问,提升了应用的性能。本期,我们将为大家介绍方舟开发框架中容器类的各种类型以及相关API的使用。

一、容器类API介绍

在方舟开发框架中,提供了线性和非线性两类容器类,共14种,每种容器都有自身的特性及使用场景。下面,我们将为大家一一道来。


(一)线性容器类

线性容器类底层主要通过数组实现,包括ArrayList、Vector、List、LinkedList、Deque、Queue、Stack七种。线性容器类API,充分考虑了数据访问的速度,实现了运行时(Runtime)通过一条指令就可以完成增删改查等操作。


1. ArrayList

ArrayList即动态数组,可用来构造全局的数组对象。ArrayList依据泛型定义,要求存储位置是一片连续的内存空间,初始容量大小为10,并支持动态扩容,每次扩容大小为原始容量的1.5倍。ArrayList进行增、删、改、查操作的相关API如下:

2. Vector
Vector 是指连续存储结构,可用来构造全局的数组对象。Vector依据泛型定义,要求存储位置是一片连续的内存空间,初始容量大小为10,并支持动态扩容,每次扩容大小为原始容量的2倍。
由于Vector扩容速度高于ArrayList,所以适用于数据添加比较频繁的场景。Vector在支持操作符访问的基础上,还增加了get/set接口,提供更为完善的校验及容错机制,满足用户不同场景下的需求。Vector进行增、删、改、查操作的相关API如下:

3. List
List可用来构造一个单向链表对象,即只能通过头结点开始访问到尾节点。List依据泛型定义,在内存中的存储位置可以是不连续的。
可以通过get/set等接口对存储的元素进行修改,List进行增、删、改、查操作的相关API如下:

4. LinkedList
LinkedList可用来构造一个双向链表对象,可以在某一节点向前或者向后遍历List。LinkedList依据泛型定义,在内存中的存储位置可以是不连续的。
可以通过get/set等接口对存储的元素进行修改,LinkedList进行增、删、改、查操作的相关API如下:

5. Queue
Queue可用来构造队列对象,存储元素遵循先进先出的规则。Queue依据泛型定义,要求存储位置是一片连续的内存空间,初始容量大小为8,并支持动态扩容,每次扩容大小为原始容量的2倍。Queue底层采用循环队列实现,入队及出队操作效率都比较高。Queue进行增、删、改、查操作的相关API如下:

6. Deque
Deque可用来构造双端队列对象,存储元素遵循先进先出的规则,双端队列可以分别从对头或者队尾进行访问。Deque依据泛型定义,要求存储位置是一片连续的内存空间,其初始容量大小为8,并支持动态扩容,每次扩容大小为原始容量的2倍。Deque底层采用循环队列实现,入队及出队操作效率都比较高。Deque进行增、删、改、查操作的相关API如下:

7. Stack
Stack可用来构造栈对象,存储元素遵循后进先出的规则。Stack依据泛型定义,要求存储位置是一片连续的内存空间,初始容量大小为8,并支持动态扩容,每次扩容大小为原始容量的1.5倍。Stack底层基于数组实现,入栈出栈均从数组的一端操作,Stack进行增、删、改、查操作的相关API如下:

(二)非线性容器类

非线性容器类底层通过hash或者红黑树实现,包括HashMap、HashSet、TreeMap、TreeSet、LightWeightMap、LightWeightSet、PlainArray七种。非线性容器类中的key及value的类型均满足ECMA标准。


1. HashMap

HashMap可用来存储具有关联关系的key-value键值对集合,存储元素中key是的,每个key会对应一个value值。HashMap依据泛型定义,集合中通过key的hash值确定其存储位置,从而快速找到键值对。HashMap的初始容量大小为16,并支持动态扩容,每次扩容大小为原始容量的2倍。HashMap底层基于HashTable实现,冲突策略采用链地址法。HashMap进行增、删、改、查操作的相关API如下:

2. HashSet
HashSet可用来存储一系列值的集合,存储元素中value是的。依据泛型定义。集合中通过value的hash值确定其存储位置,从而快速找到该值。HashSet初始容量大小为16,支持动态扩容,每次扩容大小为原始容量的2倍。value的类型满足ECMA标准中要求的类型。HashSet底层基于HashTable实现,冲突策略采用链地址法。HashSet进行增、删、改、查操作的相关API如下:

3. TreeMap
TreeMap可用来存储具有关联关系的key-value键值对集合,存储元素中key是的,每个key会对应一个value值。TreeMap依据泛型定义,集合中的key值是有序的,TreeMap的底层是一棵二叉树,可以通过树的二叉查找快速的找到键值对。key的类型满足ECMA标准中要求的类型。TreeMap中的键值是有序存储的。TreeMap底层基于红黑树实现,可以进行快速的插入和删除。TreeMap进行增、删、改、查操作的相关API如下:

4. TreeSet
TreeSet可用来存储一系列值的集合,存储元素中value是的。TreeSet依据泛型定义,集合中的value值是有序的,TreeSet的底层是一棵二叉树,可以通过树的二叉查找快速的找到该value值,value的类型满足ECMA标准中要求的类型。TreeSet中的值是有序存储的。TreeSet底层基于红黑树实现,可以进行快速的插入和删除。TreeSet进行增、删、改、查操作的相关API如下:

5. LightWeightMap
LigthWeightMap可用来存储具有关联关系的key-value键值对集合,存储元素中key是的,每个key会对应一个value值。LigthWeightMap依据泛型定义,采用更加轻量级的结构,集合中的key值的查找依赖于hash值以及二分查找算法,通过一个数组存储hash值,然后映射到其他数组中的key值以及value值,key的类型满足ECMA标准中要求的类型。
初始默认容量大小为8,每次扩容大小为原始容量的2倍。LigthWeightMap底层标识key通过hash实现,其冲突策略为线性探测法,查找策略基于二分查找法。LigthWeightMap进行增、删、改、查操作的相关API如下:

6. LightWeightSet
LigthWeightSet可用来存储一系列值的集合,存储元素中value是的。LigthWeightSet依据泛型定义,采用更加轻量级的结构,初始默认容量大小为8,每次扩容大小为原始容量的2倍。集合中的value值的查找依赖于hash以及二分查找算法,通过一个数组存储hash值,然后映射到其他数组中的value值,value的类型满足ECMA标准中要求的类型。
LigthWeightSet底层标识value基于hash实现,其冲突策略为线性探测法,查找策略基于二分查找法。LigthWeightSet进行增、删、改、查操作的相关API如下:

7. PlainArray
PlainArray可用来存储具有关联关系的键值对集合,存储元素中key是的,并且对于PlainArray来说,其key的类型为number类型。每个key会对应一个value值,类型依据泛型的定义,PlainArray采用更加轻量级的结构,集合中的key值的查找依赖于二分查找算法,然后映射到其他数组中的value值。
初始默认容量大小为16,每次扩容大小为原始容量的2倍。PlainArray的查找策略基于二分查找法。PlainArray进行增、删、改、查操作的相关API如下:

二、容器类的实现

下面我们将以ArrayList为例,为大家介绍,容器类的实现。包括容器类的初始化、容器类的接口调用、容器类对象模型的构建以及拦截器处理。


(一)容器类初始化

在方舟开发框架中,通过NAPI的统一框架对外层提供容器类。下面,我们将以ArrayList为例,介绍基于NAPI的容器类的加载。如下图所示,是容器类初始化流程,在NAPI加载的过程中,会通过ArkPrivate.Load接口加载对应的容器类。ArrayList在引擎中会初始化Constructor以及Prototype并返回,后应用侧可以获得该容器类并使用。

图1 容器类初始化流程

相关文章