当前位置: 首页 > news >正文

java容器类

一、  容器类:

下图摘自《Java编程思想》,很好地展示了整个容器类的结构。

 

 

 

由上图可知,容器类库可分为两大类,各自实现了Collection接口和Map接口,下面就常见的类进行一下分类:

实现Collection接口的容器类

Collection 
├List 
│├LinkedList 
│├ArrayList 
│└Vector 
│ └Stack 
├Set 

│├TreeSet
│└HashSet

└LinkedHashSet 

├Queue

│├LinkedList 

│├DelayQueue
│└PriorityQueue

实现Map接口的容器类

Map 
├HashMap 

└LinkedHashMap

├Hashtable

├IdentityHashMap

├TreeMap
└WeakHashMap

容器类由两个顶层接口自上而下扩展:

  • Collection: 存放独立元素的序列
  • Map:存放key—value类型的键值对元素。

  其中值得注意的是:Collection提供了Iterable()模式,可以获取到Iterator对集合内的元素进行遍历,而Map则需要先得到Collection进而得到Iterator进行遍历。

  其中 接口List、Set、Queue实现了Collection接口,对应的List、Set和Queue又有其具有实现的类。实现了Map接口的主要有HashMap、LinkedHashMap、Hashtable、IdentityHashMap、TreeMap、WeakHashMap。

 

二、  实现Collection接口的容器类

  下面就List、Set和Queue下的几种常见容器展开简要的介绍

2.1  List接口

  两种典型实现:

  • LinkedList:

  底层实现为链表,对于这种实现结构而言,插入和删除操作效率高,而随机访问元素时效率较ArrayList低。

  同时,又由于LinkedList实现了Deque接口,故而它还能提供List接口中没有定义的方法,专门用于操作表头和表尾的元素,可以当做堆栈和队列使用。

  • ArrayList:

底层实现为数组,此种结构在随机访问和查询时效率高,而在进行插入和删除操作时效率较低。此外,由于其底层实现是数组,故而当数组大小不足需要增加存储空间时,就需要将现有数组中已有的数据复制到新的存储空间中。

两种弃用的List实现:

  • Vector:

Vector和ArrayList一样也是通过数组实现的,故而其特性和ArrayList类似(Vector底层数组实现在扩容时是扩展1倍,而ArrayList则扩展50%+1个),其中值得特别注意的一点是Vector是一种线程安全的容器,即在某一时刻只有一个线程能够写Vector,避免在多线程同时写时引起的不一致性,但由于实现同步(synchronized关键字)需要较高的代价,故访问速度较慢。

  • Stack:

是Vector的一个子类,实现了一个标准的后进先出的栈。(现在实现堆栈的功能一般使用LinkedList)

2.2 Set接口

是一种不包含重复元素的Collection,同时Set允许null元素。加入set的元素必须定义equals()方法来确保对象的唯一性。

几种典型的实现:

  • Hashset:

利用哈希函数进行了查询效率上的优化,是一种为快速查找而设计的Set,存入其中的元素必须定义hashCode();

  • LinkedHashSet:

具有Hashset的查询速度,且内部使用链表来维护元素的顺序。元素同样必须定义HashCode()方法

  • TreeSet:

    保持有序的Set(实现了SortedSet接口),底层结构为红黑树,使用它可以从Set中得到有序的序列。元素必须实现Comparable接口

2.3  Queue接口:

  • PriorityQueue:

    存储在其中的元素该需要实现Comparable接口,即自己完成优先级的定义

  • Deque:

    双向队列,可以在任何一段添加或移除元素。其中LinkedList实现了Deque接口,可实现队列或栈的数据结构。

三、实现Map接口的容器类

  Map没有继承Collection的接口,其提供了key到value的映射,一个Map中不能包含相同的key,每个key只能映射一个value。

  几种典型的实现:

  • Hashtable:

  线程安全

  任何非空(non-null)的对象都可作为key或者value。

  添加数据使用put(key, value),取出数据使用get(key),这两个基本操作的时间开销为常数。

通过initial capacity和load factor两个参数调整性能。通常缺省的load factor 0.75较好地实现了时间和空间的均衡。增大load factor可以节省空间但相应的查找时间将增大,这会影响像get和put这样的操作。

由于key的对象将通过计算其散列函数确定与之对应的value的位置,因此任何作为key的对象必须实现hashcode和equeals方法。

  • HashMap:

线程不安全

HashMap和Hashtable类似,不同之处在于HashMap是非同步的,并且允许null,即null value和null key,但是将HashMap视为Collection时(values()方法可返回Collection),其迭代子操作时间开销和HashMap的容量成比例。因此,如果迭代操作的性能相当重要的话,不要将HashMap的初始化容量设得过高,或者load factor过低

  • IdentityHashMap:

比较键(和值)时使用引用“==”代替equal。即在 IdentityHashMap 中,当且仅当 (k1==k2) 时,才认为两个键 k1 和 k2 相等

而在正常 Map 实现(如 HashMap)中,当且仅当满足下列条件时才认为两个键 k1 和 k2 相等:(k1==null ? k2==null : e1.equals(e2)))。

该类是应用于特定场景下,即当我们必须使用地址相等来判断值相等的场合,以及我们确定只要其地址不相等,则其equals方法的结果也必定不相等的场合。

一个很好的例子就是线程本地存储中的ThreadLocal类,该类的原理是根据Thread从其内部的Map中获取线程独立的值,那么当我们使用只判断地址相等的IdentityHashMap就会比HashMap要快一些。

  • WeakHashMap:
    WeakHashMap是一种改进的HashMap,它对key实行“弱引用”,如果一个key不再被外部所引用,那么该key可以被GC回收。
  • ConcurrentHashMap

线程安全的Map,与HashTable不同的,它的线程安全的实现不涉及到同步加锁,它引入了一个“分段锁”的概念,即将一个大的Map拆分成多个”HashTable”(实质上是Segment),当多线程访问容器中不同数据段的数据时,线程间就不存在锁的竞争关系。

ConcurrentHashMap是由Segment数组和HashEntry数组结构组成。其中Segment是一种可重入锁,HashEntry则用于存储键值对数据。

Segment的结构和HashMap类似,是一种数组和链表的结构。一个Segment中包含一个HashEntry数组。每个HashEntry是一个链表结构的元素。每个Segment守护着 一个HashEntry中的元素,当要对HashEntry数组的数据进行修改时,必须首先获得与它对应的Segment锁。

三、怎么选用容器类

  在日常开发中,怎么选用合适的容器类关乎到程序的性能以及正确性等,所以怎么选用合适的容器类很关键。

  首先一点,容器类中存储的都是对象的引用,而非对象本身。出于便利的角度,一般简称对象的引用为对象。正如上面讲到的不同的容器存储的对象类型不同,并且具有的方法也不同,或是在进行相同操作时的效率也存在差异。

  简单来讲,我们将存储的对象分为元素和键值对两种。

  元素一般采用实现Collection接口的容器类存储。又根据元素是否有序(TreeSet),元素是否唯一有所区别(实现Set接口的类),是否要求线程安全(Vector),常进行的操作(ArrayList和LinkedList的选用)等要求进行筛选;

  而键值对则采用实现Map接口的容器类进行存储,又根据是否要求线程安全(ConcurrentHashMap)、是否有必要进行内存的释放(针对内存优化的WeakHashMap)、是否要求有序(TreeMap)、IdentityHashMap(是否可以用==替换equals来提示效率)等要求来进行筛选。

 

转载于:https://www.cnblogs.com/zhangyingai/p/7087362.html

相关文章:

  • Oracle表连接方式之等值连接、外部连接
  • eclipse环境下,java操作MySQL的简单演示
  • 牛人博客链接
  • oracle执行计划相关概念
  • 日常(委屈到爆炸)
  • oracle SQL表执行路径(表扫描方式)
  • 并发编程(四):ThreadLocal从源码分析总结到内存泄漏
  • 表之间的连接
  • 【剑指Offer面试题】九度OJ1384:二维数组中的查找
  • 查看执行计划
  • oracle11g的内存分配不当,导致的错误ORA-01034,ORA-00838,ORA-27101
  • 如何改变oracle的执行计划(HINT)
  • 【Java线程】SwingWorker的用法
  • 如何分析执行计划
  • ipconfig提示不是内部或外部命令
  • ABAP的include关键字,Java的import, C的include和C4C ABSL 的import比较
  • canvas 绘制双线技巧
  • Cumulo 的 ClojureScript 模块已经成型
  • Django 博客开发教程 16 - 统计文章阅读量
  • Docker: 容器互访的三种方式
  • Effective Java 笔记(一)
  • E-HPC支持多队列管理和自动伸缩
  • JAVA之继承和多态
  • Less 日常用法
  • magento 货币换算
  • nginx 负载服务器优化
  • WinRAR存在严重的安全漏洞影响5亿用户
  • 从PHP迁移至Golang - 基础篇
  • 模仿 Go Sort 排序接口实现的自定义排序
  • 前嗅ForeSpider教程:创建模板
  • 如何胜任知名企业的商业数据分析师?
  • 使用Maven插件构建SpringBoot项目,生成Docker镜像push到DockerHub上
  • 线上 python http server profile 实践
  • 详解移动APP与web APP的区别
  • 新手搭建网站的主要流程
  • MyCAT水平分库
  • # 数据结构
  • #14vue3生成表单并跳转到外部地址的方式
  • #AngularJS#$sce.trustAsResourceUrl
  • #NOIP 2014# day.1 生活大爆炸版 石头剪刀布
  • #调用传感器数据_Flink使用函数之监控传感器温度上升提醒
  • $L^p$ 调和函数恒为零
  • ( 用例图)定义了系统的功能需求,它是从系统的外部看系统功能,并不描述系统内部对功能的具体实现
  • (初研) Sentence-embedding fine-tune notebook
  • (附源码)spring boot火车票售卖系统 毕业设计 211004
  • (附源码)ssm高校社团管理系统 毕业设计 234162
  • (佳作)两轮平衡小车(原理图、PCB、程序源码、BOM等)
  • (排序详解之 堆排序)
  • (使用vite搭建vue3项目(vite + vue3 + vue router + pinia + element plus))
  • (一)Spring Cloud 直击微服务作用、架构应用、hystrix降级
  • (原创)boost.property_tree解析xml的帮助类以及中文解析问题的解决
  • (转)Oracle存储过程编写经验和优化措施
  • (转)微软牛津计划介绍——屌爆了的自然数据处理解决方案(人脸/语音识别,计算机视觉与语言理解)...
  • .libPaths()设置包加载目录
  • .locked1、locked勒索病毒解密方法|勒索病毒解决|勒索病毒恢复|数据库修复