<转>Java集合框架之小结

2023-11-04

转载自:http://jiangzhengjun.iteye.com/blog/553191

1、Java容器类库的简化图,下面是集合类库更加完备的图。包括抽象类和遗留构件(不包括Queue的实现): 


2、ArrayList初始化时不可指定容量,如果以new ArrayList()方式创建时,初始容量为10个;如果以new ArrayList(Collection c)初始化时,容量为c.size()*1.1,即增加10%的容量;当向ArrayList中添加一个元素时,先进行容器的容量调整,如果容量不够时,则增加至原来的1.5倍加1,再然后把元素加入到容器中,即以原始容量的0.5倍比率增加。


3、Vector:初始化时容量可以设定,如果以new Vector()方式创建时,则初始容量为10,超过容量时以2倍容量增加。如果以new Vector(Collection c)方式创建时,初始容量为c.size()*1.1,超过时以2倍容量增加。如果以new Vector(int initialCapacity, int capacityIncrement),则以capacityIncrement容量增加。

 

4、集合特点:

  • List:保证以某种特定插入顺序来维护元素顺序,即保持插入的顺序,另外元素可以重复。
  • ArrayList:是用数组实现的,读取速度快,插入与删除速度慢(因为插入与删除时要移动后面的元素),适合于随机访问。
  • Vector:功能与ArrayList几乎相同,也是以数组实现,添加,删除,读取,设置都是基于线程同步的。
  • LinkedList:双向链表来实现,删除与插入速度快,读取速度较慢,因为它读取时是从头向尾(如果节点在链的前半部分),或尾向头(如果节点在链的后半部分)查找元素。因此适合于元素的插入与删除操作。
  • Set:维持它自己的内部排序,随机访问不具有意义。另外元素不可重复。
  • HashSet:是最常用的,查询速度最快,因为 内部以HashMap来实现,所以插入元素不能保持插入次序。
  • LinkedHashSet:继承了HashSet,保持元素的插入次序,因为内部使用LinkedHashMap实现,所以能保持元素插入次序。
  • TreeSet:基于TreeMap,生成一个总是处于排序状态的set,它实现了SortedSet接口,内部以 TreeMap来实现
  • TreeMap:键以某种排序规则排序,内部以red-black(红-黑)树数据结构实现,实现了SortedMap接口,具体可参《RED-BLACK(红黑)树的实现TreeMap源码阅读 》
  • HashMap: 以哈希表数据结构实现,查找对象时通过哈希函数计算其位置,它是为快速查询而设计的,其内部定义了一个hash表数组(Entry[] table),元素会通过哈希转换函数将元素的哈希地址转换成数组中存放的索引,如果有冲突,则使用散列链表的形式将所有相同哈希地址的元素串起来,可能通过查看HashMap.Entry的源码它是一个单链表结构。
  • Hashtable:也是以哈希表数据结构实现的,解决冲突时与HashMap也一样也是采用了散列链表的形式,不过性能比HashMap要低。
  • LinkedHashMap:继承HashMap,内部实体LinkedHashMap.Entry继承自HashMap.Entry,LinkedHashMap.Entry在HashMap.Entry的基础上新增了两个实体引用(Entry before, after),这样实体可以相互串链起来形成链,并且在LinkedHashMap中就定义了一个头节点(Entry header)用来指向循环双向链的第一个元素(通过after指向)与最后一个元素(通过before指向)。在添加一个元素时,先会通过父类HashMap将元素加入到hash表数组里,然后再会在链尾(header.before指向位置)添加(当然这一过程只是调整LinkedHashMap.Entry对象内部的before, after而已,而不是真真创建一个什么新的链表结构向里加那样);删除先从hash表数组中删除,再将被删除的元素彻底的从双向链中断开。其实在链中添加与删除操作与LinkedList是一样的,可以参考《Java集合框架之LinkedList及ListIterator实现源码分析 》

5、Hashtable和HashMap的区别:

  • Hashtable中的方法是同步的,而HashMap中的方法在缺省情况下是非同步的。在多线程应用程序中,我们应该使用Hashtable;而对于HashMap,则需要额外的同步机制。但HashMap的同步问题可通过Collections的一个静态方法得到解决:Map Collections.synchronizedMap(Map m),当然与可以自己在使用地方加锁。
  • 在HashMap中,可以允许null作为键,且只可以有一个,否则覆盖,但可以有一个或多个值为null。因为当get()方法返回null值时,即可以表示 HashMap中没有该键,也可以表示该键所对应的值为null,所以HashMap不能由get()方法来判断否存在某个键,而应该用containsKey()方法来判断;而Hashtable不允许null键与null值。
  • HashTable使用Enumeration,HashMap使用Iterator。
  • Hashtable是Dictionary的子类,HashMap是Map接口的一个实现类;
  • HashTable中hash table数组默认大小是11,增加的方式是 int newCapacity = oldCapacity * 2 + 1;,即增加至2倍(而不是2倍加1,因为扩容是在增加元素前进行的,在扩容后会将新增元素放入容器中)。HashMap中hash数组的默认大小是16,而且一定是2的多少次方;另外两者的默认负载因子都是0.75。
  • 求哈希地址与哈希地址转hash数组(Entry table[])索引方法不同:

HashTable直接使用对象的hashCode:

Java代码    收藏代码
  1. int hash = key.hashCode();//直接使用键的hashCode方法求哈希值  
  2. //哈希地址转hash数组索引,先使用最大正int数与,这样将负转正数,再与数组长度求模得到存入的hash数组索引位置  
  3. int index = (hash & 0x7FFFFFFF) % tab.length;  

而HashMap重新计算hash值,而且用位运算&代替求模:

Java代码    收藏代码
  1. int hash = hash(k);  
  2. int i = indexFor(hash, table.length);  
  3.   
  4. static int hash(Object x) {  
  5. //以键本身的hash码为基础求哈希地址,但看不懂是什么意思  
  6.   int h = x.hashCode();  
  7.   h += ~(h << 9);  
  8.   h ^= (h >>> 14);  
  9.   h += (h << 4);  
  10.   h ^= (h >>> 10);  
  11.   return h;  
  12. }  
  13. static int indexFor(int h, int length) {  
  14.   return h & (length-1);//将哈希地址转换成哈希数组中存入的索引号  
  15. }  

  HashMap实现图:


6、集合中键值是否允许null小结

  • List:可以有多个null,可以有重复值。
  • HashSet:能插入一个null(因为内部是以 HashMap实现 ),忽略不插入重复元素。
  • TreeSet:不能插入null (因为内部是以 TreeMap 实现  ,元素不能重复,如果待插入的元素存在,则忽略不插入,对元素进行排序。
  • HashMap:允许一个null键与多个null值,若重复键,则覆盖以前值。
  • TreeMap:不允许null键(实际上可以插入一个null键,如果这个Map里只有一个元素是不会报错的,因为一个元素时没有进行排序操作,也就不会报空指针异常,但如果插入第二个时就会立即报错),但允许多个null值,覆盖已有键值。
  • HashTable:不允许null键与null值(否则运行进报空指针异常)。也会覆盖以重复值。基于线程同步。

7、对List的选择:

  • 对于随机查询与迭代遍历操作,数组比所有的容器都要快。
  • 从中间的位置插入和删除元素,LinkedList要比ArrayList快,特别是删除操作。
  • Vector通常不如ArrayList快,则且应该避免使用,它目前仍然存在于类库中的原因是为了支持过去的代码。
  • 最佳实践:将ArrayList作为默认首选,只有当程序的性能因为经常从list中间进行插入和删除而变差的时候,才去选择LinkedList。当然了,如果只是使用固定数量的元素,就应该选择数组了。

8、对Set的选择:

  • HashSet的性能总比TreeSet好(特别是最常用的添加和查找元素操作)。
  • TreeSet存在的唯一原因是,它可以维持元素的排序状态,所以只有当你需要一个排好序的Set时,才应该使用TreeSet。
  • 对于插入操作,LinkedHashSet比HashSet略微慢一点:这是由于维护链表所带来额外开销造成的。不过,因为有了链表,遍历LinkedHashSet会比HashSet更快。

9、对Map的选择:

  • Hashtable和HashMap的效率大致相同(通常HashMap更快一点,所以HashMap有意取代Hashtable)。
  • TreeMap通常比HashMap慢,因为要维护排序。
  • HashMap正是为快速查询而设计的。
  • LinkedHashMap比HashMap慢一点,因为它维护散列数据结构的同时还要维护链表。

10、Stack基于线程安全,Stack类是用Vector来实现的(public class Stack extends Vector),但最好不要用集合API里的这个实现栈,因为它继承于Vector,本就是一个错误的设计,应该是一个组合的设计关系。

 

11、Iterator对ArrayList(LinkedList)的操作限制:

  • 刚实例化的迭代器如果还没有进行后移(next)操作是不能马上进行删除与修改操作的。
  • 可以用ListIterator对集合连续添加与修改,但不能连续删除。
  • 进行添加操作后是不能立即进行删除与修改操作的。
  • 进行删除操作后可以进行添加,但不能进行修改操作。
  • 进行修改后是可以立即进行删除与添加操作的。

12、当以自己的对象做为HashMap、HashTable、LinkedHashMap、HashSet 、LinkedHashSet 的键时,一定要重写hashCode ()与equals ()方法,因为Object的hashCode()是返回内存地址,且equals()方法也是比较内存地址,所以当要在这些hash集合中查找时,如果是另外new出的新对象是查不到的,除非重写这两个方法。因为AbstractMap类的containsKey(Object key)方法实现如下:

Java代码    收藏代码
  1. if (e.hash == hash && eq(k, e.key))//先比对hashcode,再使用equals  
  2.     return true;  
  3.   
  4. static boolean eq(Object x, Object y) {  
  5.     return x == y || x.equals(y);  
  6. }  

String对象是可以准确做为键的,因为已重写了这两个方法。

 

因此,Java中的集合框架中的哈希是以一个对象查找另外一个对象,所以重写hasCode与equals方法很重要。 

13、重写hashCode()与equals()这两个方法是针对哈希类,至于其它集合,如果要用public boolean contains(Object o)或containsValue(Object value)查找时,只需要实现equals()方法即可,他们都只使用对象的
 equals方法进行比对,没有使用hashCode方法。 

14、TreeMap/TreeSet:放入其中的元素一定要具有自然比较能力(即要实现java.lang.Comparable接口)或者在构造TreeMap/TreeSet时传入一个比较器(实现java.util.Comparator接口),如果在创建时没有传入比较器,而放入的元素也没有自然比较能力时,会出现类型转换错误(因为在没有较器时,会试着转成Comparable型)。


两种比较接口:

Java代码    收藏代码
  1. //自然比较器  
  2. public interface java.lang.Comparable {  
  3.     public int compareTo(Object o);  
  4. }  
  5.   
  6. public interface java.util.Comparator {  
  7.     int compare(Object o1, Object o2);  
  8.     boolean equals(Object obj);  
  9. }  

 

15、Collection或Map的同步控制:可以使用Collections类的相应静态方法来包装相应的集合类,使他们具线程安全,如public static Collection synchronizedCollection (Collection c)方法实质返回的是包装后的SynchronizedCollection子类,当然你也可以使用Collections的synchronizedList、synchronizedMap、synchronizedSet方法来获取不同的经过包装了的同步集合,其代码片断:

Java代码    收藏代码
  1. public class Collections {  
  2.   
  3.     //...  
  4.   
  5.     static Collection synchronizedCollection(Collection c, Object mutex) {  
  6.         return new SynchronizedCollection(c, mutex);  
  7.     }  
  8.   
  9.     public static List synchronizedList(List list) {  
  10.         //...  
  11.     }  
  12.   
  13.     static Set synchronizedSet(Set s, Object mutex) {  
  14.         //...  
  15.     }  
  16.   
  17.     public static Map synchronizedMap(Map m) {  
  18.         return new SynchronizedMap(m);  
  19.     }  
  20.   
  21.     //...  
  22.     static class SynchronizedCollection implements Collection, Serializable {  
  23.   
  24.         Collection c; // 对哪个集合进行同步(包装)  
  25.         Object mutex; // 对象锁,可以自己设置  
  26.   
  27.         //...  
  28.         SynchronizedCollection(Collection c, Object mutex) {  
  29.             this.c = c;  
  30.             this.mutex = mutex;  
  31.         }  
  32.   
  33.         public int size() {  
  34.             synchronized (mutex) {  
  35.                 return c.size();  
  36.             }  
  37.         }  
  38.   
  39.         public boolean isEmpty() {  
  40.             synchronized (mutex) {  
  41.                 return c.isEmpty();  
  42.             }  
  43.         }  
  44.         //...  
  45.     }  
  46.   
  47.     static class SynchronizedList 
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

<转>Java集合框架之小结 的相关文章

随机推荐

  • vue中的ref之间的通信

    vue文档对ref的官方解释是 ref 被用来给元素或子组件注册引用信息 引用信息将会注册在父组件的 refs 对象上 如果在普通的 DOM 元素上使用 引用指向的就是 DOM 元素 如果用在子组件上 引用就指向组件实例 p hello p
  • 从用户登录谈谈测试用例设计

    等价类划分和边界值分析方法是最常用 最典型并且是最重要的黑盒测试方法 一 功能测试用例 针对 用户登录 功能测试 基于等价类划分和边界值分析方法 能够设计的功能测试用例有 1 输入已注册的用户名和正确的密码 验证是否登录成功 2 输入已注册
  • 干货满满!MES生产制造管理全流程分析

    阅读本文您将了解 1 什么是MES生产管理流程 2 MES生产管理流程具体步骤 3 实施MES生产管理流程优势 4 MES生产管理流程中可能会遇见的问题 一 什么是MES生产管理流程 MES生产管理系统 又称制造执行系统 是一种集成了计划
  • C语言--库函数qsort排序

    文章目录 一 C语言 库函数qsort排序 1 1 冒泡排序 1 2 qsort排序 二 模拟实现qsort函数 一 C语言 库函数qsort排序 假设我们要对一个数组元素进行排序 如果是一个整型数组 我们首先可以想到的是冒泡排序 但其实C
  • 腾讯潘安群:腾讯云金融级数据库TDSQL分析

    SDCC 2015将于2015年11月19 21日在北京 朗丽姿西山花园酒店召开 在大会召开之际 笔者采访到了腾讯高级软件工程师潘安群 请他分享TDSQL在腾讯云金融领域的实践经验 SDCC 2015将于2015年11月19 21日在北京
  • python语法--文件基本操作(一)

    python语法 文件基本操作 文件基本操作 打开文件 open name mode encoding name 文件名 可以包括路径 mode 设置打开文件的模式 只读r 写入w 追加a等 encoding 编码格式 推荐utf 8 f
  • layui实现Tree组件前后端交互

    文章目录 前言 运行效果 Tree组件 1 Tree组件的加载方式 1 1选项卡 2 Tree组件的渲染格式 3 基础参数 4 数据源属性选项 后台代码实现 1 定义对应数据格式实体 2 数据转换 3 树结构存储的处理 角色处理 1 思路
  • Zookeeper巨坑的一个问题 & 启动不了zkServer-闪退等情况

    1 配置环境变量 不然无法启动服务 2 此时不应有 java jdk1 8 cmd报这种错误 第一检查java环境变量是否错误 是否包含空格 第二就是我这种情况 一定要注意打开服务需要64位目录下的java
  • C++ 结束进程

    有时候进程未正常退出 导致进程列表遗留僵尸进程 程序启动需要杀死这种僵尸进程 include TLHELP32 H void TerminateSelfApplication TCHAR szFileName MAX PATH 0 TCHA
  • jmeter接口应用3:jmeter后置处理器-正则表达式提取器

    今天将继续讲解jmeter中关于后置处理器中的用法 也叫提取器 详情参考 https www toutiao com article 7195493970682692154 正则表达式提取器 正则表达式提取器提取内容有两种 一种是提取字符串
  • div向右偏移设置 css让div靠右移一定距离

    转自 https www thinkcss com shili 1372 shtml div对象盒子向右偏移设置 使用css让div靠右一定距离 div向右移教程实例篇 div向右偏移一定距离 可采用margin外边距实现 也可以使用pad
  • shell脚本模块化

    shell脚本模块化 模块化的优点 功能清晰 易于维护 便于阅读 代码复用 源代码 只有单一的一个run sh文件 bin bash 功能 更新小程序并重新启动 设置程序出错时不再继续执行 set e 查找app的进程号并杀死该进程 ech
  • 网络端口号和协议号(大全)

    网络端口号 作用 端口号的主要作用是表示一台计算机中的特定进程所提供的服务 网络中的计算机是通过IP地址来代表其身份的 它只能表示某台特定的计算机 但是一台计算机上可以同时提供很多个服务 如数据库服务 FTP服务 web服务等 我们就通过端
  • python中哈希表和set的使用

    哈希表不能将可变对象作为key值 即引用类型的内容不能是可变的 这样不安全 因为hashcode函数是根据对象的内容计算出key和value的位置 如果引用的内容可变 那么每次查找的位置结果都不一样 之前存储的键值对就会找不到 不符合has
  • 区块链技术之分布式存储

    随着互联网技术应用技术的普遍使用 所有行业的数据量指数级增长 数据存储技术都需要更新 分布式存储是一种数据存储技术 它可以跨多个物理服务器传播文件 块存储或者对象存储 以实现高可用性 数据备份和灾难恢复目的 可扩展的存储服务以及数据中心的巨
  • K8S的金丝雀发布(Canary Release)

    金丝雀发布 Canary Release 1 概念 2 相关架构理念 3 金丝雀发布部署操作 4 访问测试 5 金丝雀隔离新的pod 6 重建 7 获取当前集群中所有的终结点 8 登录旧的pod中测试 9 查看更新状态信息 总结 1 概念
  • 树链剖分

    树链剖分 两个核心思想 将一棵树转化成一个序列 树中路径转化成 log n 段连续区间 相关概念 重儿子 某个节点的子节点所构成的子树中 子树节点数量最多对应的子节点为重儿子 如果有多个相同的最大数量 则任选一个为重儿子 也就是说 每个节点
  • Node.js 创建一个简单的web服务器

    Node可以写 web服务器 命令行工具 网络爬虫 桌面应用程序开发等 今天 我们利用node写一个简单的web服务器 一 引入主模块 let http require http 二 创建一个服务器 createServer可以看到源码注入
  • 微信小程序子页面自定义tabbar组件

    一 先言 有时候微信小程序会遇到代码合并 就比如把B小程序代码迁移到A小程序 要使得B作为A小程序的一个子页面子功能 因为本身小程序都有tabbar 原来B也有 这时候就要给B子功能自定义一个tabbar底部导航栏 注意 这个不是微信小程序
  • <转>Java集合框架之小结

    转载自 http jiangzhengjun iteye com blog 553191 1 Java容器类库的简化图 下面是集合类库更加完备的图 包括抽象类和遗留构件 不包括Queue的实现 2 ArrayList初始化时不可指定容量 如