[Java语言] HashMap,HashSet,Hashtable,Vector,ArrayList 的关系 <转>
这么几个比较常用的但是比较容易混淆的概念同出于 java.util 包。本文仅作几个类的浅度解析。
(本文基于JDK1.7,源码来自openjdk1.7。)
- ├── Collection
- │ ├── List
- │ │ ├── ArrayList
- │ │ ├── Vector
- │ │ └── LinkedList and so on;
- │ Set
- │ ├── HashSet
- │ └── LinkedHashSet and so on;
- └── Map
- ├── Hashtable
- ├── HashMap
- └── WeakHashMap and so on;
复制代码
Collection和Map
按理来说和这两者没有什么特别关系。然而本文中仍然将这两个混在一起:
第一,HashSet,HashMap,Hashtable长得太像了,没有理由不写再一起。
第二,HashSet是个Set,其实骨子里是个Map。
List
继承List的类,泛型为Integer时,注意和其他的类型不同。(因为Index是Integer)
线程安全
简单来说,List是个一维数组。Vector和ArrayList区别在于:
Vector是个线程安全的,而ArrayList不是。这点看源码可以看出来,Vector中各种synchronized,甚至连size属性都丧心病狂地synchronized了。
同样,Iterator指定Vector和ArrayList,如果中间发生变化则会抛出ConcurrentModificationException异常。
不仅仅是List,很多地方的Iterator都有这个异常,
自增大小
ArrayList没办法设置自增大小,但是仍然可以自增。
Vector可以设置自增大小。
ArrayList的自增函数:
Vector的自增函数:
- private void grow(int minCapacity) {
- // overflow-conscious code
- int oldCapacity = elementData.length;
- int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
- capacityIncrement : oldCapacity);
- //在这里,如果没有设置自增大小的话,那么默认自增大小则是原来的Vector大小。
- if (newCapacity - minCapacity < 0)
- newCapacity = minCapacity;
- if (newCapacity - MAX_ARRAY_SIZE > 0)
- newCapacity = hugeCapacity(minCapacity);
- elementData = Arrays.copyOf(elementData, newCapacity);
- }
复制代码
ArrayList自增函数:
- private void grow(int minCapacity) {
- // overflow-conscious code
- int oldCapacity = elementData.length;
- int newCapacity = oldCapacity + (oldCapacity >> 1);
- //新长度则是旧长度的大小加上一个移位运算(一半的大小)。
- if (newCapacity - minCapacity < 0)
- newCapacity = minCapacity;
- if (newCapacity - MAX_ARRAY_SIZE > 0)
- newCapacity = hugeCapacity(minCapacity);
- // minCapacity is usually close to size, so this is a win:
- elementData = Arrays.copyOf(elementData, newCapacity);
- }
复制代码
所以可以简单的认为Vector默认自增一倍的长度,ArrayList则是默认自增一半的长度。
同样,对他们的源码分析:
Vector可以设置自增大小,而ArrayList则无法设置(没有这个构造方法)。
- public Vector(int initialCapacity, int capacityIncrement)
复制代码
最后,可以 List list=new ArrayList<>();,然后list=new Vector<>();,使用基类List可以实现ArrayList和Vector的快速赋值。
Map
Map可以当成是简单的“Key-Value”数据库,例如memcached和redis。
Hashtable基于Directory,有种说法是Directory已经过时,所以更推荐使用Map。
线程安全
Hashtable也是线程安全的,和Vector一样,连size函数都丧心病狂地同步了。
- public synchronized
int size() { - return count;
- }
复制代码
HashMap不是线程安全的,当然也可以用其他的黑科技实现同步,例如SynchronizedMap和ConcurrentHashMap。
那个以后再说……
空值
HashMap允许在Key和Value中都出现null值。例如:
- v.toString()
- {null=null, 1=66, 2=null, 3=4d, 4=0f, 5=null}
复制代码
而Hashtable则不允许K/V的任何一个出现null值,但是允许空字符串。
- Hashtable<String,String> v=new Hashtable<String,String>();
- v.put("3s",null);
复制代码
直接报错:java.lang.NullPointerException。
这个和内部实现有关,Hashtable需要用到hashCode,所以必须要确保K/V不为null。
相关代码写死在源码里:
- public synchronized V put(K key, V value) {
- // Make sure the value is not null
- if (value == null) {
- throw new NullPointerException();
- }
- //下面对hashCode做点事情。
复制代码
Set
HashSet本质上是一个Collection,类似于List,是列表/集合,不是K-V的Map,但是它骨子里是一个HashMap……
这么说可能会更易于理解:
HashSet对外是“类”的集合,实际上是内部维护了一个HashMap进行实现。
实际上存储的是两个:hashCode和类本身(字符串/自定义类等)。
HashSet进行add的时候,会先进行验证hashCode:
(HashSet进行add操作实际上是对Map的put操作)
- public V put(K key, V value) {
- if (table == EMPTY_TABLE) {
- inflateTable(threshold);
- }
- if (key == null)
- return putForNullKey(value);
- int hash = hash(key);//本函数里有hashCode
- int i = indexFor(hash, table.length);
- for (Entry<K,V> e = table[i]; e != null; e = e.next) {
- Object k;
- if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
- V oldValue = e.value;
- e.value = value;
- e.recordAccess(this);
- return oldValue;
- }
- }
- modCount++;
- addEntry(hash, key, value, i);
- return null;
- }
复制代码
一个对HashSet的自定义类的操作:
- class Name
- {
- private String first;
- private String last;
- public Name(String first, String last)
- {
- this.first = first;
- this.last = last;
- }
- public boolean equals(Object o)
- {
- if (this == o)
- {
- return true;
- }
- if (o.getClass() == Name.class)
- {
- Name n = (Name)o;
- return n.first.equals(first)
- && n.last.equals(last);
- }
- return false;
- }
- }
- public class HashSetTest
- {
- public static void main(String[] args)
- {
- Set<Name> s = new HashSet<Name>();
- s.add(new Name("abc", "123"));
- System.out.println(
- s.contains(new Name("abc", "123")));
- }
- }
复制代码
代码来自java中HashSet详解
粗看上去是会返回true的,实际返回false。因为 HashSet 判断两个对象相等的标准除了要求通过 equals()
方法比较返回 true 之外,还要求两个对象的 hashCode() 返回值相等。而上面程序没有重写 Name 类的 hashCode()
方法,两个 Name 对象的 hashCode() 返回值并不相同,因此 HashSet 会把它们当成 2 个对象处理,因此程序返回
false。如果想返回true,需要重写equals方法和hashCode方法。
至于hashCode,就是另一篇文章才解释得清的了。
集合操作
Set其实做集合操作更加简单。例如:
- import java.util.*;
- public class SetOperation {
- public static void main(String[] args) {
- Set<Integer> result = new HashSet<Integer>();
- Set<Integer> set1 = new HashSet<Integer>(){{
- add(1);
- add(3);
- add(5);
- }};
- Set<Integer> set2 = new HashSet<Integer>(){{
- add(1);
- add(2);
- add(3);
- }};
- result.clear();
- result.addAll(set1);
- result.retainAll(set2);
- System.out.println("交集:"+result);
- result.clear();
- result.addAll(set1);
- result.removeAll(set2);
- System.out.println("差集:"+result);
- result.clear();
- result.addAll(set1);
- result.addAll(set2);
- System.out.println("并集:"+result);
- }
- }
复制代码
输出:
- 交集:[1, 3]
- 差集:[5]
- 并集:[1, 2, 3, 5]
复制代码
参考文档
hashSet中的equals方法和hashCode方法
《http://bbs.it-home.org/thread-53825-1-1.html?ref=myread》
[Java语言] HashMap,HashSet,Hashtable,Vector,ArrayList 的关系 <转>的更多相关文章
- Java 集合 HashMap & HashSet 拾遗
Java 集合 HashMap & HashSet 拾遗 @author ixenos 摘要:HashMap内部结构分析 Java HashMap采用的是冲突链表方式 从上图容易看出,如果选择 ...
- Java的HashMap和HashTable
Java的HashMap和HashTable 1. HashMap 1) hashmap的数据结构 Hashmap是一个数组和链表的结合体(在数据结构称“链表散列“),如下图示: 当我们往hashm ...
- ArrayList,Vector,HashMap,HashSet,HashTable之间的区别与联系
在编写java程序中,我们最常用的除了八种基本数据类型,String对象外还有一个集合类,在我们的的程序中到处充斥着集合类的身影!java中集合大家族的成员实在是太丰富了,有常用的ArrayList. ...
- LinkedList,ArrayList,Vector,HashMap,HashSet,HashTable之间的区别与联系
在编写java程序中,我们最常用的除了八种基本数据类型,String对象外还有一个集合类,在我们的的程序中到处充斥着集合类的身影!java中集合大家族的成员实在是太丰富了,有常用的ArrayList. ...
- java集合HashMap、HashTable、HashSet详解
一.Set和Map关系 Set代表集合元素无序,集合元素不可重复的集合,Map代表一种由多个key-value组成的集合,map集合是set集合的扩展只是名称不同,对应如下 二.HashMap的工作原 ...
- Java的HashMap和Hashtable有什么区别HashSet和HashMap有什么区别?使用这些结构保存的数需要重载的方法是哪些?
HashMap与Hashtable实现原理相同,功能相同,底层都是哈希表结构,查询速度快,在很多情况下可以互用 两者的主要区别如下 1.Hashtable是早期JDK提供的接口,HashMap是新版J ...
- java中 HashMap和Hashtable,list、set和map 的区别
摘自: http://blog.chinaunix.net/uid-7374279-id-2057584.html HashMap是Hashtable的轻量级实现(非线程安全的实现),他们都完成了Ma ...
- JAVA中HashMap和Hashtable区别
Hashtable和HashMap在Java面试中相当容易被问到,甚至成为了集合框架面试题中最常被考的问题,所以在参加任何Java面试之前,都不要忘了准备这一题. 我们先看2个类的定义 public ...
- Java集合——HashMap、HashTable以及ConCurrentHashMap异同比较
0. 前言 HashMap和HashTable的区别一种比较简单的回答是: (1)HashMap是非线程安全的,HashTable是线程安全的. (2)HashMap的键和值都允许有null存在,而H ...
随机推荐
- java资料——链表(转)
链表 链表是一种物理存储单元上非连续.非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的.链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成.每个结点包括两个 ...
- openwrt内核配置选项添加
摘自:http://blog.csdn.net/weiniliuchao/article/details/50295527 增加内核配置选项 openwrt的.config文件中,关于内核的选项都是形 ...
- 机器学习:K-Means聚类算法
本文来自同步博客. 前面几篇文章介绍了回归或分类的几个算法,它们的共同点是训练数据包含了输出结果,要求算法能够通过训练数据掌握规律,用于预测新输入数据的输出值.因此,回归算法或分类算法被称之为监督学习 ...
- PHP无限极分类 - 2 - 无限极评论
参考上一节: 结合ZUI前端框架,制作的无限极评论列表: 项目目录: 代码: <!DOCTYPE html> <html lang="en"> <he ...
- jQuery Masonry-让你的网页更自然的强大的动态不规则布局插件!
Masonry是 一款非常强大的jQuery动态网格布局插件,可以帮助开发人员快速开发类似剪贴画的界面效果.和CSS中float的效果不太一样的地方在 于,float先水平排列,然后再垂直排列,使用M ...
- QT全局宏变量的实现
qt中如何实现定义一个宏,在整个工程中都可以实现呢?下面我来写一个亲测的例子: pro中添加如下宏定义代码: DEFINES += HELLO=\"$$PWD/\" DEFINES ...
- Spark1.0.0 学习路线指导
转自:http://www.aboutyun.com/thread-8421-1-1.html 问题导读1.什么是spark?2.spark编程模型是什么?3.spark运维需要具有什么知识?4.sp ...
- PHP 初探
由于不可描述的原因,需要运行一个PHP项目,折腾了半天却无甚效果---概念缺失. 一怒之下,决定还是先了解下PHP本身再说.先得感谢下W3School,介绍简洁明了. PHP是脚本语言! PHP不需要 ...
- vs2013+MVC3.0+EasyUI的ComboBox联动使用(二)
vs2013+MVC3.0+EasyUI的ComboBox联动使用(二) 简单介绍:在vs2013(.net4.0)中使用MVC3.0对于EasyUI中ComboBox的联动使用. 载入Comb ...
- 动态调用WCF不添加服务(svcutil.exe)
记录下 首先用svcutil.exe把指定wcf接口的信息下载下来. 生成代理类 比如说接口地址为 http://localhost:6666/Service1.svc 以管理员身份打开cmd 执形 ...