共计 6369 个字符,预计需要花费 16 分钟才能阅读完成。
作者:liuxin,华为高级工程师
容器类,顾名思义就是存储的类,用于存储各种数据类型的元素,并具备一系列解决数据元素的办法。在方舟开发框架中,容器类采纳了相似动态的语言来实现,并通过 NAPI 框架对外提供。通过对存储地位以及属性的限度,让每种类型的数据都能在实现本身性能的根底上剪除冗余分支,保障了数据的高效拜访,晋升了利用的性能。本期,咱们将为大家介绍方舟开发框架中容器类的各种类型以及相干 API 的应用。
一、容器类 API 介绍
在方舟开发框架中,提供了线性和非线性两类容器类,共 14 种,每种容器都有本身的个性及应用场景。上面,咱们将为大家一一道来。
1
线性容器类
线性容器类底层次要通过数组实现,包含 ArrayList、Vector、List、LinkedList、Deque、Queue、Stack 七种。线性容器类 API,充分考虑了数据拜访的速度,实现了运行时(Runtime)通过一条指令就能够实现增删改查等操作。
- ArrayList
ArrayList 即动静数组,可用来结构全局的数组对象。ArrayList 根据泛型定义,要求存储地位是一片间断的内存空间,初始容量大小为 10,并反对动静扩容,每次扩容大小为原始容量的 1.5 倍。ArrayList 进行增、删、改、查操作的相干 API 如下:
- Vector
Vector 是指间断存储构造,可用来结构全局的数组对象。Vector 根据泛型定义,要求存储地位是一片间断的内存空间,初始容量大小为 10,并反对动静扩容,每次扩容大小为原始容量的 2 倍。
因为 Vector 扩容速度高于 ArrayList,所以实用于数据增加比拟频繁的场景。Vector 在反对操作符拜访的根底上,还减少了 get/set 接口,提供更为欠缺的校验及容错机制,满足用户不同场景下的需要。Vector 进行增、删、改、查操作的相干 API 如下:
- List
List 可用来结构一个单向链表对象,即只能通过头结点开始拜访到尾节点。List 根据泛型定义,在内存中的存储地位能够是不间断的。
能够通过 get/set 等接口对存储的元素进行批改,List 进行增、删、改、查操作的相干 API 如下:
- LinkedList
LinkedList 可用来结构一个双向链表对象,能够在某一节点向前或者向后遍历 List。LinkedList 根据泛型定义,在内存中的存储地位能够是不间断的。
能够通过 get/set 等接口对存储的元素进行批改,LinkedList 进行增、删、改、查操作的相干 API 如下:
- Queue
Queue 可用来结构队列对象,存储元素遵循先进先出的规定。Queue 根据泛型定义,要求存储地位是一片间断的内存空间,初始容量大小为 8,并反对动静扩容,每次扩容大小为原始容量的 2 倍。Queue 底层采纳循环队列实现,入队及出队操作效率都比拟高。Queue 进行增、删、改、查操作的相干 API 如下:
- Deque
Deque 可用来结构双端队列对象,存储元素遵循先进先出的规定,双端队列能够别离从对头或者队尾进行拜访。Deque 根据泛型定义,要求存储地位是一片间断的内存空间,其初始容量大小为 8,并反对动静扩容,每次扩容大小为原始容量的 2 倍。Deque 底层采纳循环队列实现,入队及出队操作效率都比拟高。Deque 进行增、删、改、查操作的相干 API 如下:
- Stack
Stack 可用来结构栈对象,存储元素遵循后进先出的规定。Stack 根据泛型定义,要求存储地位是一片间断的内存空间,初始容量大小为 8,并反对动静扩容,每次扩容大小为原始容量的 1.5 倍。Stack 底层基于数组实现,入栈出栈均从数组的一端操作,Stack 进行增、删、改、查操作的相干 API 如下:
2、非线性容器类
非线性容器类底层通过 hash 或者红黑树实现,包含 HashMap、HashSet、TreeMap、TreeSet、LightWeightMap、LightWeightSet、PlainArray 七种。非线性容器类中的 key 及 value 的类型均满足 ECMA 规范。
- HashMap
HashMap 可用来存储具备关联关系的 key-value 键值对汇合,存储元素中 key 是惟一的,每个 key 会对应一个 value 值。HashMap 根据泛型定义,汇合中通过 key 的 hash 值确定其存储地位,从而疾速找到键值对。HashMap 的初始容量大小为 16,并反对动静扩容,每次扩容大小为原始容量的 2 倍。HashMap 底层基于 HashTable 实现,抵触策略采纳链地址法。HashMap 进行增、删、改、查操作的相干 API 如下:
- HashSet
HashSet 可用来存储一系列值的汇合,存储元素中 value 是惟一的。根据泛型定义。汇合中通过 value 的 hash 值确定其存储地位,从而疾速找到该值。HashSet 初始容量大小为 16,反对动静扩容,每次扩容大小为原始容量的 2 倍。value 的类型满足 ECMA 规范中要求的类型。HashSet 底层基于 HashTable 实现,抵触策略采纳链地址法。HashSet 进行增、删、改、查操作的相干 API 如下:
- TreeMap
TreeMap 可用来存储具备关联关系的 key-value 键值对汇合,存储元素中 key 是惟一的,每个 key 会对应一个 value 值。TreeMap 根据泛型定义,汇合中的 key 值是有序的,TreeMap 的底层是一棵二叉树,能够通过树的二叉查找疾速的找到键值对。key 的类型满足 ECMA 规范中要求的类型。TreeMap 中的键值是有序存储的。TreeMap 底层基于红黑树实现,能够进行疾速的插入和删除。TreeMap 进行增、删、改、查操作的相干 API 如下:
- TreeSet
TreeSet 可用来存储一系列值的汇合,存储元素中 value 是惟一的。TreeSet 根据泛型定义,汇合中的 value 值是有序的,TreeSet 的底层是一棵二叉树,能够通过树的二叉查找疾速的找到该 value 值,value 的类型满足 ECMA 规范中要求的类型。TreeSet 中的值是有序存储的。TreeSet 底层基于红黑树实现,能够进行疾速的插入和删除。TreeSet 进行增、删、改、查操作的相干 API 如下:
- LightWeightMap
LigthWeightMap 可用来存储具备关联关系的 key-value 键值对汇合,存储元素中 key 是惟一的,每个 key 会对应一个 value 值。LigthWeightMap 根据泛型定义,采纳更加轻量级的构造,汇合中的 key 值的查找依赖于 hash 值以及二分查找算法,通过一个数组存储 hash 值,而后映射到其余数组中的 key 值以及 value 值,key 的类型满足 ECMA 规范中要求的类型。
初始默认容量大小为 8,每次扩容大小为原始容量的 2 倍。LigthWeightMap 底层标识惟一 key 通过 hash 实现,其抵触策略为线性探测法,查找策略基于二分查找法。LigthWeightMap 进行增、删、改、查操作的相干 API 如下:
- LightWeightSet
LigthWeightSet 可用来存储一系列值的汇合,存储元素中 value 是惟一的。LigthWeightSet 根据泛型定义,采纳更加轻量级的构造,初始默认容量大小为 8,每次扩容大小为原始容量的 2 倍。汇合中的 value 值的查找依赖于 hash 以及二分查找算法,通过一个数组存储 hash 值,而后映射到其余数组中的 value 值,value 的类型满足 ECMA 规范中要求的类型。
LigthWeightSet 底层标识惟一 value 基于 hash 实现,其抵触策略为线性探测法,查找策略基于二分查找法。LigthWeightSet 进行增、删、改、查操作的相干 API 如下:
- PlainArray
PlainArray 可用来存储具备关联关系的键值对汇合,存储元素中 key 是惟一的,并且对于 PlainArray 来说,其 key 的类型为 number 类型。每个 key 会对应一个 value 值,类型根据泛型的定义,PlainArray 采纳更加轻量级的构造,汇合中的 key 值的查找依赖于二分查找算法,而后映射到其余数组中的 value 值。
初始默认容量大小为 16,每次扩容大小为原始容量的 2 倍。PlainArray 的查找策略基于二分查找法。PlainArray 进行增、删、改、查操作的相干 API 如下:
二、容器类的实现
上面咱们将以 ArrayList 为例,为大家介绍,容器类的实现。包含容器类的初始化、容器类的接口调用、容器类对象模型的构建以及拦截器解决。
1. 容器类初始化
在方舟开发框架中,通过 NAPI 的对立框架对外层提供容器类。上面,咱们将以 ArrayList 为例,介绍基于 NAPI 的容器类的加载。如下图所示,是容器类初始化流程,在 NAPI 加载的过程中,会通过 ArkPrivate.Load 接口加载对应的容器类。ArrayList 在引擎中会初始化 Constructor 以及 Prototype 并返回,最初利用侧能够取得该容器类并应用。
图 1 容器类初始化流程
2. 容器类接口调用
在方舟开发框架中,容器类 API 的调用流程如图 2 所示,用户先通过 new ArrayList 进入引擎失去对应的 arraylist 对象,而后能够通过 add 接口向对象中增加元素,元素最终会增加到一片和该 arraylist 绑定的内存空间。能够通过 [] 操作符进行元素获取,对于容器类而言,引擎会间接通过疾速门路拜访到元素存储地位,返回该值。
图 2 容器类 API 的调用流程
3. 容器类对象模型
在方舟开发框架中,结构容器类对象模型的流程如下图所示,在运行时禁止再向对象上增加 Properties 属性,ArrayList 借用对象模型中的 elements 地位存储元素。
图 3 容器类对象模型的结构流程
实现阐明:通过 elements 存储数组元素,Length 为数组中元素个数,数组 Capatity 能够通过 elements 的长度获取。
扩容策略:ArrayList –> 1.5 倍
初始调配容量:ArrayList -> 10
(注:TS 中的实现,扩容策略及初始调配容量不感知)
4. 拦截器解决
拦截器解决,是指通过禁止掉一些影响对象行为的操作,比方 delete、setPrototype 等,在运行时(Runtime)保护一个高效的容器类对象。如图 4 所示,以 ArrayList 为例,ArkCompiler 外部拦挡的操作次要波及 DeleteProperty、DefineProperty、GetProperty、SetPrototype、GetOwnPropertyKeys、HasProperty 等操作限度数组的 holy 增加,以及更改属性的 attributes 等操作,保障了不须要做 JSArray 必须做的 holy 判断、writable 判断等操作。
图 4 拦截器解决
三、容器类 API 的应用
通过上文的介绍,置信大家对容器类曾经有了比拟粗浅的意识。那么,咱们怎么应用容器类 API 呢?本文列举罕用的典型容器的应用示例,包含导入模块、减少元素、拜访元素及批改等操作:
// ArrayList
import ArrayList from '@ohos.util.ArrayList' // 导入 ArrayList 模块
let arrayList = new ArrayList();
arrayList.add("a");
arrayList.add(1); // 减少元素
print(arrayList[0]); // 拜访元素
arrayList[0] = one"; // 批改元素
print(arrayList[0]);
// Vector
import Vector from '@ohos.util.Vector' // 导入 Vector 模块
let vector = new Vector();
vector.add("a");
let b = [1, 2, 3];
vector.add(b);
vector.add(false); // 减少元素
print(vector[0]); // 拜访元素
print(vector.getFirstElement()); // 拜访元素
// Deque
import Deque from '@ohos.util.Deque' // 导入 Deque 模块
let deque = new Deque;
deque.insertFront("a");
deque.insertFront(1); // 减少元素
print(deque[0]); // 拜访元素
deque[0] = "one"; // 批改元素
print(deque[0]);
// Stack
import Stack from '@ohos.util.Stack' // 导入 Stack 模块
let stack = new Stack();
stack.push("a");
stack.push(1); // 减少元素
print(stack[0]); // 拜访元素
stack.pop(); // 弹出元素
print(stack.length);
// List
import List from '@ohos.util.List' // 导入 List 模块
let list = new List;
list.add("a");
list.add(1);
let b = [1, 2, 3];
list.add(b); // 减少元素
print(list[0]); // 拜访元素
print(list.get(0)); // 拜访元素
// HashMap
import HashMap from '@ohos.util.HashMap' // 导入 HashMap 模块
let hashMap = new HashMap();
hashMap.set("a", 123);
hashMap.set(4, 123); // 减少元素
print(hashMap.hasKey(4)); // 判断是否含有某元素
print(hashMap.get("a")); // 拜访元素
// TreeMap
import TreeMap from '@ohos.util.TreeMap' // 导入 TreeMap 模块
let treeMap = new TreeMap();
treeMap.set("a", 123);
treeMap.set("6", 356); // 减少元素
print(treeMap.get("a")); // 拜访元素
print(treeMap.getFirstKey("a")); // 拜访首元素
print(treeMap.getLastKey("a")); // 拜访尾元素
// LightWeightMap
import LightWeightMap from '@ohos.util.LightWeightMap' // 导入 LightWeightMap 模块
let lightWeightMap = new LightWeightMap();
lightWeightMap.set("x", 123);
lightWeightMap.set("8", 356); // 减少元素
print(lightWeightMap.get("a")); // 拜访元素
print(lightWeightMap.get("x")); // 拜访元素
print(lightWeightMap.getIndexOfKey("8")); // 拜访元素
// PlainArray
import PlainArray from '@ohos.util.PlainArray' // 导入 PlainArray 模块
let plainArray = new PlainArray();
plainArray.add(1, "sdd");
plainArray.add(2, "sff"); // 减少元素
print(plainArray.get(1)); // 拜访元素
print(plainArray.getKeyAt(1)); // 拜访元素
至此以上就是本期全部内容,期待宽广开发者通过方舟开发框架的容器类开发出更多高性能的利用。