这么几个比较常用的但是比较容易混淆的概念同出于 java.util 包。本文仅作几个类的浅度解析。
(本文基于JDK1.7,源码来自openjdk1.7。)

  1. ├── Collection
  2. │ ├── List
  3. │ │ ├── ArrayList
  4. │ │ ├── Vector
  5. │ │ └── LinkedList and so on;
  6. │ Set
  7. │ ├── HashSet
  8. │ └── LinkedHashSet and so on;
  9. └── Map
  10. ├── Hashtable
  11. ├── HashMap
  12. └── 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的自增函数:

  1. private void grow(int minCapacity) {
  2. // overflow-conscious code
  3. int oldCapacity = elementData.length;
  4. int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
  5. capacityIncrement : oldCapacity);
  6. //在这里,如果没有设置自增大小的话,那么默认自增大小则是原来的Vector大小。
  7. if (newCapacity - minCapacity < 0)
  8. newCapacity = minCapacity;
  9. if (newCapacity - MAX_ARRAY_SIZE > 0)
  10. newCapacity = hugeCapacity(minCapacity);
  11. elementData = Arrays.copyOf(elementData, newCapacity);
  12. }

复制代码

ArrayList自增函数:

  1. private void grow(int minCapacity) {
  2. // overflow-conscious code
  3. int oldCapacity = elementData.length;
  4. int newCapacity = oldCapacity + (oldCapacity >> 1);
  5. //新长度则是旧长度的大小加上一个移位运算(一半的大小)。
  6. if (newCapacity - minCapacity < 0)
  7. newCapacity = minCapacity;
  8. if (newCapacity - MAX_ARRAY_SIZE > 0)
  9. newCapacity = hugeCapacity(minCapacity);
  10. // minCapacity is usually close to size, so this is a win:
  11. elementData = Arrays.copyOf(elementData, newCapacity);
  12. }

复制代码

所以可以简单的认为Vector默认自增一倍的长度,ArrayList则是默认自增一半的长度。

同样,对他们的源码分析:
Vector可以设置自增大小,而ArrayList则无法设置(没有这个构造方法)。

  1. 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函数都丧心病狂地同步了。

  1. public synchronized
    int size() {
  2. return count;
  3. }

复制代码

HashMap不是线程安全的,当然也可以用其他的黑科技实现同步,例如SynchronizedMap和ConcurrentHashMap。
那个以后再说……

空值

HashMap允许在Key和Value中都出现null值。例如:

  1. v.toString()
  2. {null=null, 1=66, 2=null, 3=4d, 4=0f, 5=null}

复制代码

而Hashtable则不允许K/V的任何一个出现null值,但是允许空字符串。

  1. Hashtable<String,String> v=new Hashtable<String,String>();
  2. v.put("3s",null);

复制代码

直接报错:java.lang.NullPointerException。
这个和内部实现有关,Hashtable需要用到hashCode,所以必须要确保K/V不为null。

相关代码写死在源码里:

  1. public synchronized V put(K key, V value) {
  2. // Make sure the value is not null
  3. if (value == null) {
  4. throw new NullPointerException();
  5. }
  6. //下面对hashCode做点事情。

复制代码

Set

HashSet本质上是一个Collection,类似于List,是列表/集合,不是K-V的Map,但是它骨子里是一个HashMap……

这么说可能会更易于理解:
HashSet对外是“类”的集合,实际上是内部维护了一个HashMap进行实现。

实际上存储的是两个:hashCode和类本身(字符串/自定义类等)。

HashSet进行add的时候,会先进行验证hashCode:
(HashSet进行add操作实际上是对Map的put操作)

  1. public V put(K key, V value) {
  2. if (table == EMPTY_TABLE) {
  3. inflateTable(threshold);
  4. }
  5. if (key == null)
  6. return putForNullKey(value);
  7. int hash = hash(key);//本函数里有hashCode
  8. int i = indexFor(hash, table.length);
  9. for (Entry<K,V> e = table[i]; e != null; e = e.next) {
  10. Object k;
  11. if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
  12. V oldValue = e.value;
  13. e.value = value;
  14. e.recordAccess(this);
  15. return oldValue;
  16. }
  17. }
  18. modCount++;
  19. addEntry(hash, key, value, i);
  20. return null;
  21. }

复制代码

一个对HashSet的自定义类的操作:

  1. class Name
  2. {
  3. private String first;
  4. private String last;
  5. public Name(String first, String last)
  6. {
  7. this.first = first;
  8. this.last = last;
  9. }
  10. public boolean equals(Object o)
  11. {
  12. if (this == o)
  13. {
  14. return true;
  15. }
  16. if (o.getClass() == Name.class)
  17. {
  18. Name n = (Name)o;
  19. return n.first.equals(first)
  20. && n.last.equals(last);
  21. }
  22. return false;
  23. }
  24. }
  25. public class HashSetTest
  26. {
  27. public static void main(String[] args)
  28. {
  29. Set<Name> s = new HashSet<Name>();
  30. s.add(new Name("abc", "123"));
  31. System.out.println(
  32. s.contains(new Name("abc", "123")));
  33. }
  34. }

复制代码

代码来自java中HashSet详解

粗看上去是会返回true的,实际返回false。因为 HashSet 判断两个对象相等的标准除了要求通过 equals()
方法比较返回 true 之外,还要求两个对象的 hashCode() 返回值相等。而上面程序没有重写 Name 类的 hashCode()
方法,两个 Name 对象的 hashCode() 返回值并不相同,因此 HashSet 会把它们当成 2 个对象处理,因此程序返回
false。如果想返回true,需要重写equals方法和hashCode方法。

至于hashCode,就是另一篇文章才解释得清的了。

集合操作

Set其实做集合操作更加简单。例如:

  1. import java.util.*;
  2. public class SetOperation {
  3. public static void main(String[] args) {
  4. Set<Integer> result = new HashSet<Integer>();
  5. Set<Integer> set1 = new HashSet<Integer>(){{
  6. add(1);
  7. add(3);
  8. add(5);
  9. }};
  10. Set<Integer> set2 = new HashSet<Integer>(){{
  11. add(1);
  12. add(2);
  13. add(3);
  14. }};
  15. result.clear();
  16. result.addAll(set1);
  17. result.retainAll(set2);
  18. System.out.println("交集:"+result);
  19. result.clear();
  20. result.addAll(set1);
  21. result.removeAll(set2);
  22. System.out.println("差集:"+result);
  23. result.clear();
  24. result.addAll(set1);
  25. result.addAll(set2);
  26. System.out.println("并集:"+result);
  27. }
  28. }

复制代码

输出:

  1. 交集:[1, 3]
  2. 差集:[5]
  3. 并集:[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 的关系 <转>的更多相关文章

  1. Java 集合 HashMap & HashSet 拾遗

    Java 集合 HashMap & HashSet 拾遗 @author ixenos 摘要:HashMap内部结构分析 Java HashMap采用的是冲突链表方式 从上图容易看出,如果选择 ...

  2. Java的HashMap和HashTable

    Java的HashMap和HashTable 1. HashMap 1)  hashmap的数据结构 Hashmap是一个数组和链表的结合体(在数据结构称“链表散列“),如下图示: 当我们往hashm ...

  3. ArrayList,Vector,HashMap,HashSet,HashTable之间的区别与联系

    在编写java程序中,我们最常用的除了八种基本数据类型,String对象外还有一个集合类,在我们的的程序中到处充斥着集合类的身影!java中集合大家族的成员实在是太丰富了,有常用的ArrayList. ...

  4. LinkedList,ArrayList,Vector,HashMap,HashSet,HashTable之间的区别与联系

    在编写java程序中,我们最常用的除了八种基本数据类型,String对象外还有一个集合类,在我们的的程序中到处充斥着集合类的身影!java中集合大家族的成员实在是太丰富了,有常用的ArrayList. ...

  5. java集合HashMap、HashTable、HashSet详解

    一.Set和Map关系 Set代表集合元素无序,集合元素不可重复的集合,Map代表一种由多个key-value组成的集合,map集合是set集合的扩展只是名称不同,对应如下 二.HashMap的工作原 ...

  6. Java的HashMap和Hashtable有什么区别HashSet和HashMap有什么区别?使用这些结构保存的数需要重载的方法是哪些?

    HashMap与Hashtable实现原理相同,功能相同,底层都是哈希表结构,查询速度快,在很多情况下可以互用 两者的主要区别如下 1.Hashtable是早期JDK提供的接口,HashMap是新版J ...

  7. java中 HashMap和Hashtable,list、set和map 的区别

    摘自: http://blog.chinaunix.net/uid-7374279-id-2057584.html HashMap是Hashtable的轻量级实现(非线程安全的实现),他们都完成了Ma ...

  8. JAVA中HashMap和Hashtable区别

    Hashtable和HashMap在Java面试中相当容易被问到,甚至成为了集合框架面试题中最常被考的问题,所以在参加任何Java面试之前,都不要忘了准备这一题. 我们先看2个类的定义 public ...

  9. Java集合——HashMap、HashTable以及ConCurrentHashMap异同比较

    0. 前言 HashMap和HashTable的区别一种比较简单的回答是: (1)HashMap是非线程安全的,HashTable是线程安全的. (2)HashMap的键和值都允许有null存在,而H ...

随机推荐

  1. OpenWRT中的按键和灯的GPIO控制实现

    基于BarrierBreaker版本,基于AR9331 AP121 Demo单板 来进行描述 1.灯 A.在mach-ap121.c中,定义了灯所对应的GPIO定义: #define AP121_GP ...

  2. 部署zookeeper集群

    1.把zookeeper.tar.gz解压之后,移动到/usr目录下 2.首先要给zookeeper之间的每个节点的ssh设置无密码登陆 3.在zookeeper目录下编辑zoo.cfg,复制zoo_ ...

  3. DataGridView使用技巧三:不显示最下面的新行、判断新增行

    一.DataGridView不显示下面的新行 通常DataGridView的最下面一行是用户新追加的行(行头显示*).如果不想让用户新追加行即不想显示该新行,可以将DataGridView对象的All ...

  4. 谈API网关的背景、架构以及落地方案

    Chris Richardson曾经在他的博客上详细介绍过API网关,包括API网关的背景.解决方案以及案例.对于大多数基于微服务的应用程序而言,API网关都应该是系统的入口,它会负责服务请求路由.组 ...

  5. 给原型扩展一下tirm方法

    方便以后,直记录下来 <script type="text/javascript"> //给原型护展tirm方法 String.prototype.trim=funct ...

  6. Windows通用知识讲解二

    NMAKE Makefile是一个解释执行的工具,根据Makefile文件中的定义,编译和链接程序,最终生成文件. Makefile(Windows下是.mak文件) 定义编译和链接等操作的脚本文件( ...

  7. 'cl.exe' 不是内部或外部命令,也不是可运行的程序 或批处理文件。

    1.首先找到vcvars32.bat文件,一般在C:\\Program Files (x86)\\Microsoft Visual Studio 12.0\\VC\\bin文件夹下 2.打开cmd黑窗 ...

  8. ADC相关参数之---分辨率和精度

    ADC的分辨率被定义为输入信号值的最小变化,这个最小数值变化会改变数字输出值的一个数值.对于一个理想ADC来说,传递函数是一个步宽等于分辨率的阶梯.然而,在具有较高分辨率的系统中(≥16位),传输函数 ...

  9. 【MySQL】MySQL 常用语法之锁表与解锁表

    mysql 锁表语句: Lock锁整张表: 写锁定: LOCK TABLES products WRITE: 写锁,锁定之后,只有当前线程可以进行读操作和写操作,其他线程读操作和写操作均被堵塞.... ...

  10. [转载]php设计模式之单例、多例设计模式

    单例(Singleton)模式和不常见的多例(Multiton)模式控制着应用程序中类的数量.如模式名称,单例只能实例化一次,只有一个对象,多例模式可以多次实例化. 基于Singleton的特性,我们 ...