作者: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 容器类初始化流程

(二)容器类接口调用

在方舟开发框架中,容器类API的调用流程如图2所示,用户先通过new ArrayList进入引擎得到对应的arraylist对象,然后可以通过add接口向对象中添加元素,元素最终会添加到一片和该arraylist绑定的内存空间。可以通过[]操作符进行元素获取,对于容器类而言,引擎会直接通过快速路径访问到元素存储位置,返回该值。

图2 容器类API的调用流程

(三)容器类对象模型

在方舟开发框架中,构造容器类对象模型的流程如下图所示,在运行时禁止再向对象上添加Properties属性,ArrayList借用对象模型中的elements位置存储元素。

图3 容器类对象模型的构造流程

  • 实现说明:通过elements存储数组元素,Length为数组中元素个数,数组Capatity可以通过elements的长度获取。
  • 扩容策略:ArrayList –> 1.5倍
  • 初始分配容量:ArrayList -> 10

(注:TS中的实现,扩容策略及初始分配容量不感知)

(四)拦截器处理

拦截器处理,是指通过禁止掉一些影响对象行为的操作,比如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)); // 访问元素

至此以上就是本期全部内容,期待广大开发者通过方舟开发框架的容器类开发出更多高性能的应用。

扫码添加开发者小助手微信

获取更多HarmonyOS开发资源和开发者活动资讯

HarmonyOS方舟开发框架容器类API的介绍与使用的更多相关文章

  1. OpenHarmony 3.1 Beta版本关键特性解析——ArkUI容器类API介绍

    (以下内容来自开发者分享,不代表 OpenHarmony 项目群工作委员会观点) 刘鑫 容器类,顾名思义就是存储的类,用于存储各种数据类型的元素,并具备一系列处理数据元素的方法.在 ArkUI 开发框 ...

  2. Odoo 二次开发教程(五)-新API的介绍与应用

    [关于odoo新API的介绍,Internet上资料很少,或者不够完整详实,这会对初学者造成很大的困惑,本篇的目的就是希望能帮助新手了解新API的大概] odoo 新api的实现是借助于python装 ...

  3. RDIFramework.NET ━ .NET快速信息化系统开发框架 ━ 工作流程组件介绍

    RDIFramework.NET ━ .NET快速信息化系统开发框架 工作流程组件介绍 RDIFramework.NET,基于.NET的快速信息化系统开发.整合框架,给用户和开发者最佳的.Net框架部 ...

  4. Tyk API网关介绍及安装说明

    Tyk API网关介绍及安装说明 Tyk是一个开源的轻量级API网关程序. 什么是API网关 API网关是一个各类不同API的前置服务器.API网关封装了系统内部架构,对外提供统一服务.此外还可以实现 ...

  5. spring3 的restful API RequestMapping介绍

    原文链接:http://www.javaarch.net/jiagoushi/694.htm spring3 的restful API RequestMapping介绍 在spring mvc中 @R ...

  6. RDIFramework.NET(.NET快速信息化系统开发框架) Web版介绍

    RDIFramework.NET(.NET快速信息化系统开发框架)  Web版介绍 B/S结构(Browser/Server,浏览器/服务器模式),是WEB兴起后的一种网络结构模式,WEB浏览器是客户 ...

  7. 基于Metronic的Bootstrap开发框架--工作流模块功能介绍(2)

    本篇继续<基于Metronic的Bootstrap开发框架--工作流模块功能介绍>,继续介绍基于Metronic的Bootstrap开发框架的工作模块功能,介绍工作流模块中相关业务表单的界 ...

  8. FileNet P8 工作流生命周期管理和 Process Engine API 应用介绍

    摘录:https://www.ibm.com/developerworks/cn/data/library/techarticles/dm-0902wangzheng/ FileNet P8 工作流生 ...

  9. Tesseract-OCR-05-主要API功能介绍

    Tesseract-05-主要API功能介绍 tesseract本身代码是由c/c++混编而成的,其中有用的简单的接口函数几乎都是在baseapi.h中 从其处理过程中,不难得出: 它还需要有一个im ...

随机推荐

  1. 基于Python的某大学某学院新生高考成绩分析

    # coding=gbk import pandas as pd import numpy as np import matplotlib.pyplot as plt from pylab impor ...

  2. LeetCode650

    LeetCode每日一题2021.9.19 跳转链接 分析 我们发现每个数字只能由它的因数通过复制而来, 因为复制操作是每次去添加一个相同的个数. 因此我们就可以得出DP方程 dp[i] = min( ...

  3. 【h5游戏开发】egret引擎p2物理引擎 - 小球碰撞地面搞笑的物理现象

    重力的方向和地面的问题 p2中默认的方向是从上到下,如果重力默认是正数的话,物体放到世界中是会从上面往下面飘的 p2中plane地面默认的方向是y轴的方向,而在p2中y轴的方向默认是从上往下 首先来看 ...

  4. python编写购物车

    上次的学习又没有坚持下来,工作忙的不可开交,但我反思了一下还是自己没有下定决心好好学习,所以这次为期3个月的学习计划开始了,下面是这次学习后重新编写的购物车初版代码. 1 # 功能要求: 2 # 要求 ...

  5. IDE集成git

    目录 简介 Git安装 IDE集成Git IDE集成Git代码的创建分享上传 代码的下载和普通上传 分子的创建以及合并 代码的回滚 查看历史版本 简介 Git 是一个开源的分布式版本控制软件,用以有效 ...

  6. HttpClient 的Timeout waiting for connection from pool

    Timeout waiting for connection from pool 异常 httpClient大家用到地方会很多,先简单描述一下几个关键配置的意义 httpClient版本为4.5.1 ...

  7. Android生成xml

    XmlSerializer     //使用XmlSerializer来序列化xml文件     public static boolean backupSms_android(Context con ...

  8. iOS 即使通讯第三方SDK 资料

    第三方即时通讯SDK,下面是一些主流的第三方的即时通讯SDK,尽管不能查看里面的源代码,但通过查看头文件,能为实现自己的即使通讯SDK提供很好的思路.(备用) 容云 容联.云通讯 IMSDK - 轻松 ...

  9. Linux文件系统与日志分析的了解

    Linux文件系统与日志分析 1.inode和block概述 2.模拟inode耗尽实验 3.ext类型文件恢复 4.xfs类型文件恢复 5.日志文件 6.日志分析 1.文件:文件是存储在硬盘上的,硬 ...

  10. PostgreSQL删除数据库失败处理

    PostgreSQL Drop DATABASE删除数据库失败,需要结束掉占用的连接 登录PostgreSQL后,执行: SELECT pg_terminate_backend(pg_stat_act ...