Android中List、Set、Map数据结构详解

Android中一般使用的数据结构有java中的基础数据结构List,Set,Map。还有一些Android中特有的几个,SparseArray(使用Map时Key是int类型的时候可以用这个代替)等。

继承关系:

Collection<–List<–ArrayList

Collection<–List<–Vector

Collection<–List<–LinkedList

Collection<–Set<–HashSet

Collection<–Set<–HashSet<–LinkedHashSet

Collection<–Set<–SortedSet<–TreeSet

Map<–HashMap (补充一个HashMap的子类LinkedHashMap:)

Map<–SortedMap<–TreeMap

注:这里的 Collection、List、Set和Map都是接口(Interface),其中Collection是所有集合类的接口,Set和List也都实现该接口。

下面分别来介绍List、Set、Map。

List

List是有序的Collection,使用此接口能够精确的控制每个元素插入的位置。用户能够使用索引(元素在List中的位置,类似于数组下标)来访问List中的元素,这类似于Java的数组。 List比较常用的有ArrayList和LinkedList,还有一个比较类似的Vector。

1、ArrayList

基于数组(Array)的List,ArrayList其实是对数组的动态扩充,底层的数据结构使用的是数组结构(数组长度是可变的百分之五十延长)。

特点:

对于数据的随机get和set或是少量数据的插入或删除,效率会比较高。ArrayList是线程不安全的,在不考虑线程安全的情况下速度也比较快的。ArrayList插入数据可以重复,也是有序的,按照插入的顺序来排序。性能上要比Vector(是线程安全的)好一些。

Vector

基于数组(Array)的List,Vector其实是对数组的动态扩充,底层的数据结构使用的是数组结构(数组长度是可变的百分之百延长)。

特点:

Vector的使用方法和内部实现基本和ArrayList相同,只不过它在add(), remove(), get()等方法中都加了同步。所以Vector是线程同步(sychronized)的,线程安全的。但是使用效率上就不如ArrayList了。

LinkedList

LinkedList不同于前面两个,是基于链表实现的双向链表数据结构。
它每一个节点(Node)都包含三方面的内容:

1、节点本身的数据(data)

2、前一个节点的信息(previousNode)

3、下一个节点的信息(nextNode)

所以当对LinkedList做添加,删除动作的时候就不用像基于数组的ArrayList一样,必须进行大量的数据移动。
只要更改nextNode的相关信息就可以实现了,这是LinkedList的优势。

LinkedList根据序号获取数据,是根据二分法进行遍历,如果序号小于总长度的一半,就从链表头部开始往后遍历,直到找到对应的序号。如果序号大于总长度的一半,就从链表尾部往前进行遍历,直到找到对应的序号。拿到数据。

List总结

1、所有的List中只能容纳单个不同类型的对象组成的表,而不是Key-Value键值对。例如:[ tom,1,c ]

2、所有的List中可以有相同的元素,例如Vector中可以有 [ tom,koo,too,koo ]

3、所有的List中可以有null元素,例如[ tom,null,1 ]

4、基于Array的List(Vector,ArrayList)适合查询,而LinkedList 适合添加,删除操作

Set

Set是一种不包含重复的元素的无序Collection。 一般使用的有HashSet和TreeSet。

虽然Set同List都实现了Collection接口,但是他们的实现方式却大不一样。List基本上都是以Array为基础。但是Set则是在 HashMap的基础上来实现的,这个就是Set和List的根本区别。

HashSet

HashSet是根据hashCode来决定存储位置的,是通过HashMap实现的,所以对象必须实现hashCode()方法,存储的数据无序不能重复,可以存储null,但是只能存一个。

看看 HashSet的add(Object obj)方法的实现就可以一目了然了。

public boolean add(Object obj) {   return map.put(obj, PRESENT) == null;   
}

这个也是为什么在Set中不能像在List中一样有重复的项的根本原因,因为HashMap的key是不能有重复的。

HashSet代码示例:

public class Main {public static void main(String[] args) throws IOException {hashSet();}public static void hashSet(){Set<String> set = new HashSet<String>();set.add("2");set.add("1");set.add(null);set.add("1");for(String s : set){System.out.println(s);}}
}

运行结果:

null
1
2

LinkedHashSet

HashSet的一个子类,一个链表。

它和HashSet的区别就在于LinkedHashSet的元素严格按照放入顺序排列。LinkedHashSet内部使用LinkedHashMap实现,所以它和HashSet的关系就相当于HashMap和LinkedHashMap的关系。如果你想让取出元素的顺序和插入元素的顺序完全相同,那么就使用LinkedHashSet代替HashSet。

LinkedHashSet也不是线程安全的。

TreeSet

SortedSet的子类,它不同于HashSet的根本就是TreeSet是有序的。它是通过SortedMap来实现的。TreeSet是根据二叉树实现的,也就是TreeMap,,放入数据不能重复且不能为null,可以重写comparator()方法来确定元素大小,从而进行升序排序。

代码示例:

public class Main {public static void main(String[] args) throws IOException {treeSet();}public static void treeSet(){//通过传入MyComparator对象自定义的排序方法,来实现从大到小的排序。Set<Integer> treeSet = new TreeSet<>(new MyComparator());treeSet.add(1);treeSet.add(3);treeSet.add(4);treeSet.add(2);for(Integer i : treeSet){System.out.println(i);}}static class MyComparator implements Comparator<Integer>{@Overridepublic int compare(Integer o1, Integer o2) {if(o1 < o2 ){return -1;}if(o1 == o2 ){return 0;}if(o1 > o2 ){return 1;}return 0;}}
}

运行结果:

1
2
3
4

Set总结

1、Set实现的基础是Map(HashMap)

2、Set中的元素是不能重复的,如果使用add(Object obj)方法添加已经存在的对象,则会覆盖前面的对象

Map

Map 是一种把键对象和值对象进行关联的容器,而一个值对象又可以是一个Map,依次类推,这样就可形成一个多级映射。

对于键对象来说,像Set一样,一个 Map容器中的键对象不允许重复,这是为了保持查找结果的一致性;如果有两个键对象一样,那你想得到那个键对象所对应的值对象时就有问题了,可能你得到的并不是你想的那个值对象,结果会造成混乱,所以键的唯一性很重要,也是符合集合的性质的。

当然在使用过程中,某个键所对应的值对象可能会发生变化,这时会按照最后一次修改的值对象与键对应。对于值对象则没有唯一性的要求,你可以将任意多个键都映射到一个值对象上,这不会发生任何问题(不过对你的使用却可能会造成不便,你不知道你得到的到底是那一个键所对应的值对象)。

Map有两种比较常用的实现:HashMap和TreeMap。

HashMap

HashMap是基于散列链表来实现的,简单的来说,根据key算出一个hash值,确定一个存放index,但是hash值有可能会冲突重复,所以如果冲突的hash值就需要以链表的形式在同一个index存放了。详情请看HashMap原理和代码浅析这篇文章。

代码示例:

    Map<String, String> hashMap = new HashMap<>();//存储hashMap.put("1", "abc");hashMap.put("2", "bcd");//根据key来删除hashMap.remove("1");//根据key获取String value = hashMap.get("2");//map的遍历,有很多方法遍历,这里只列举一种。for(Map.Entry<String, String> entry : hashMap.entrySet()){//获取keyentry.getKey();//获取valueentry.getValue();}

LinkedHashMap

LinkedHashMap继承自HashMap,特点是内部存入数据是有顺序的,增加了记住元素插入或者访问顺序的功能,这个是通过内部一个双向的循环链表实现的。与 HashMap 一样,它可以为基本操作(add、contains 和 remove)提供稳定的性能,假定哈希函数将元素正确分布到桶中。由于增加了维护链接列表的开支,其性能很可能比 HashMap 稍逊一筹,不过这一点例外:LinkedHashMap 的 collection 视图迭代所需时间与映射的大小 成比例。HashMap 迭代时间很可能开支较大,因为它所需要的时间与其容量 成比例。

TreeMap

TreeMap的使用大致跟HashMap类似,但是内部实现是根据红黑树来实现的。红黑树是一种平衡有序的二叉树,TreeMap的插入删除查询都是依据红黑树的规则来进行的。可以参考 Java提高篇(二七)—–TreeMap

HashTable

HashMap和TreeMap都是线程不安全的,多线程操作的时候可能会造成数据错误。Hashtable是线程安全的。其他内部实现,与HashMap都是一样的。

常用类的比较

常用类

1.ArrayList:元素单个,效率高,多用于查询

2.Vector: 元素单个,线程安全,多用于查询

3.LinkedList:元素单个,多用于插入和删除

4.HashMap:元素成对,元素可为空

5.HashTable:元素成对,线程安全,元素不可为空

6.HashSet:元素单个,元素不可重复

Vector、ArrayList和LinkedList

大多数情况下,从性能上来说ArrayList最好

当集合内的元素需要频繁插入、删除时LinkedList会有比较好的表现

它们三个性能都比不上数组,另外Vector是线程同步的

能用数组的时候(元素类型固定,数组长度固定),请尽量使用数组来代替List

没有频繁的删除插入操作,又不用考虑多线程问题,优先选择ArrayList

在多线程条件下使用,可以考虑Vector

需要频繁地删除插入,LinkedList就有了用武之地

如果你什么都不知道,用ArrayList没错。

以上是java中的基础的数据结构,下面来看下android中特有的数据结构。

SparseArray

SparseArray类型

SparseLongArray

SparseIntArray

SparseBooleanArray

SparseArray

SparseArray特点

1、SparseArray是android提供的一个工具类,它可以用来替代hashmap进行对象的存储

2、SparseArray比HashMap更省内存,它对数据采取了矩阵压缩的方式来表示稀疏数组的数据,从而节约内存空间

3、SparseArray只能存储key为整型的数据

4、SparseArray在存储和读取数据时候,使用的是二分查找法,提高了查找的效率

5、SparseArray有自己的垃圾回收机制。(当数量不是很多的时候,这个不必关心。)

ArrayMap

官方对ArrayMap也有说明:它不是一个适应大数据的数据结构,相比传统的HashMap速度要慢,因为查找方法是二分法,并且当你删除或者添加数据时,会对空间重新调整,在使用大量数据时,效率并不明显,低于50%。

所以ArrayMap是牺牲了时间换区空间。在写手机app时,适时的使用ArrayMap,会给内存使用带来可观的提升。

HashMap和ArrayMap的区别

1、存储方式不同

2、添加数据时扩容时的处理不同

详情请参考Android内存优化:ArrayMap

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/447038.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Android设计模式之——单例模式

一、介绍 单例模式是应用最广的模式之一&#xff0c;也可能是很多初级工程师唯一会使用的设计模式。在应用这个模式时&#xff0c;单例对象的类必须保证只有一个实例存在。许多时候整个系统只需要拥有一个全局对象&#xff0c;这样有利于我们协调系统整体的行为。 二、定义 …

我的职业生涯规划(软件工程)

以后笔记先在语雀整理 方便一点https://www.yuque.com/juhao-pqdor/goeie3 整理一下自己的笔记 弥补一下以前没写博客的遗憾吧 二十载求学路将尽&#xff0c;行文至此&#xff0c;思绪万千。求学之路始于家乡&#xff0c;竿转热河&#xff0c;而今终于石门。一路行之如人饮水…

C++ primer第六章6.5函数的学习 之特殊用途的语言特性

6.5.1 默认实参 将反复出现的数值称为函数的默认实参&#xff0c;调用含有默认实参的时候可以包含该实参也可以不包含比如程序打开页面会有一个默认的宽高&#xff0c;如果用户不喜欢也允许用户自由指定与默认数值不同的数值&#xff0c;具体例子如下图所示 typedef string::s…

Android设计模式之——Builder模式

一、介绍 Builder模式是一步一步创建一个复杂对象的创建型模式&#xff0c;它允许用户在不知道内部构建细节的情况下&#xff0c;可以更精细的控制对象的构造流程。该模式是为了将构建复杂对象的过程和它的部件解耦&#xff0c;使得构建过程和部件的表示隔离开来。 因为一个复…

c++后端开发书籍推荐

推荐书籍: 略读80% 精读50% C&#xff1a; C Primer Plus C和指针&#xff08;入门书 不只是指针&#xff09; C陷阱与缺陷&#xff08;宏相关&#xff09; C专家编程 C&#xff1a; 有专门的视频 C primer C程序设计原理与实践&#xff08;c之父写的 入门经典&#xff09; Ef…

C++ primer第六章6.6函数匹配

函数的匹配 当重载函数的形参数量相等以及某些形参的类型可以由其他的类型转化得来的时候&#xff0c;对于函数的匹配就会变得很难 确定候选函数和可行函数 函数匹配的第一步就是选定本次调用对应的重载函数集&#xff0c;集合中的函数称为候选函数。候选函数具有两个特征&am…

Android设计模式之——原型模式

一、介绍 原型模式是一个创建型的模式。原型二字表明了该模型应该有一个样板实例&#xff0c;用户从这个样板对象中复制出一个内部属性一致的对象&#xff0c;这个过程也就是我们俗称的“克隆”。被复制的实例就是我们所称的“原型”&#xff0c;这个原型也是可定制的。原型模…

C++ primer第六章6.7函数指针

函数指针 函数指针指向的是函数而不是对象。和其他指针一样&#xff0c;函数指针指向某种特定的类型。函数的类型由他的返回类型和形参类型共同决定&#xff0c;而与函数的名字无关。 //比较两个string对象的长度 bool lengthCompare(const string &,const string &);…

Android设计模式之——工厂方法模式

一、介绍 工厂方法模式&#xff08;Factory Pattern&#xff09;&#xff0c;是创建型设计模式之一。工厂方法模式是一种结构简单的模式&#xff0c;其在我们平时开发中应用很广泛&#xff0c;也许你并不知道&#xff0c;但是你已经使用了无数次该模式了&#xff0c;如Android…

C++ primer第十八章 18.1小结 异常处理

18.1 异常处理 异常处理机制&#xff0c;允许程序独立开发的部分能够在运行的时候出现的问题进行通信并且做出相应的处理&#xff0c;异常的处理使得我们可以将问题的检测和处理分离开来。程序的一部分负责检测问题的出现&#xff0c;然后将解决这个问题的任务传递给程序的另一…

浅谈equals与==

一、前言 示例代码&#xff1a; public static void main(String[] args) throws IOException {String str1 new String("hello");String str2 new String("hello");String str3 "cde";String str4 "cde";int i1 3;int i2 3;In…

针对C++异常的学习

源码 头文件 sdf_exception.h #pragma once#include <exception> #include <string>namespace sdf {namespace common{using sdf_error_code_t uint32_t;class SdfException : std::exception{public:explicit SdfException(sdf_error_code_t errorCode) : erro…

Android设计模式之——抽象工厂模式

一、介绍 抽象工厂模式&#xff08;Abstract Factory Pattern&#xff09;&#xff0c;也是创建型设计模式之一。前一节我们已经了解了工厂方法模式&#xff0c;那么这个抽象工厂又是怎么一回事呢&#xff1f;大家联想一下现实生活中的工厂肯定都是具体的&#xff0c;也就是说…

Android设计模式之——策略模式

一、介绍 在软件开发中也常常遇到这样的情况&#xff1a;实现某一个功能可以有多种算法或者策略&#xff0c;我们根据实际情况选择不同的算法或者策略来完成该功能。例如&#xff0c;排序算法&#xff0c;可以使用插入排序、归并排序、冒泡排序等。 针对这种情况&#xff0c;…

密码学在区块链隐私保护中的应用学习

身份隐私保护技术 混淆服务 混淆服务的目的在于混淆消息双方的联系&#xff08;如 图 2 所示&#xff09;。当发送方需要告知接收方消息 M 时&#xff0c; 它会首先用接收方的公钥 KB 加密 M&#xff0c;并在密文后 附带真实接收地址 R。为了借助第三方&#xff08;图 2 中的…

值类型和引用类型的区别

一、定义 引用类型表示你操作的数据是同一个&#xff0c;也就是说当你传一个参数给另一个方法时&#xff0c;你在另一个方法中改变这个变量的值&#xff0c;那么调用这个方法是传入的变量的值也将改变。 值类型表示复制一个当前变量传给方法&#xff0c;当你在这个方法中改变…

面向区块链的高效物化视图维护和可信查询论文学习

物化视图介绍 如何维护物化视图仍旧是一个开放问题.在关系数据库中,增量刷新的物化视图维护策略可划分为立即维护和延迟维护两大类.立即维护策略的优点是实现较为简单,在单数据源下不 存在一致性问题;然而该策略将物化视图维护过程嵌入到更新事务之中,延长了更新事务的提交时间…

Java基础知识(一)

一、接口 类描述了一个实体&#xff0c;包括实体的状态&#xff0c;也包括实体可能发出的动作。 接口定义了一个实体可能发出的动作。但是只是定义了这些动作的原型&#xff0c;没有实现&#xff0c;也没有任何状态信息。 所以接口有点象一个规范、一个协议&#xff0c;是一个…

密码学数字信封的介绍

对称密码和非对称密码 对称密码&#xff1a;加解密运算非常快&#xff0c;适合处理大批量数据&#xff0c;但其密码的分发与管理比较复杂非对称密码&#xff1a;公钥和私钥分离&#xff0c;非常适合密钥的分发和管理 数字信封的定义 如果将对称密码算法和非对称密码算法的优点…

Android设计模式之——状态模式

一、介绍 状态模式中的行为是由状态来决定的&#xff0c;不同的状态下有不同的行为。状态模式和策略模式的结构几乎完全一样&#xff0c;但它们的目的、本质却完全不一样。状态模式的行为是平行的、不可替换的&#xff0c;策略模式的行为是彼此独立、可相互替换的。用一句话来…