Java中HashMap与HashTable,StringBuilder与StringBuffer的区别

    说一个几个月前遇到的一个面试题,当时没答出来,被刷下来了,后来后悔不已。可是归根结底就是个人Java基础仍是欠缺。今天在项目中再次遇到,咱们就来回顾一下。java

Java中HashMap与HashTable的区别:面试

 Hashtable和HashMap类有三个重要的不一样之处。      安全

第一个不一样主要是历史缘由。  数据结构

Hashtable是基于陈旧的Dictionary类的,HashMap是Java 1.2引进的Map接口的一个实现。          多线程

也许最重要的不一样是Hashtable的方法是同步的,而HashMap的方法不是。 这就意味着,虽然你能够不用采起任何特殊的行为就能够在一个多线程的应用程序中用一个Hashtable,但你必须一样地为一个HashMap提供外同步。一个方便的方法就是利用Collections类的静态的synchronizedMap()方法,它建立一个线程安全的Map对象,并把它做为一个封装的对象来返回。这个对象的方法可让你同步访问潜在的HashMap。这么作的结果就是当你不须要同步时,你不能切断Hashtable中的同步(好比在一个单线程的应用程序中),并且同步增长了不少处理费用。          并发

第三点不一样是,只有HashMap可让你将空值做为一个表的条目的key或value。 HashMap中只有一条记录能够是一个空的key,但任意数量的条目能够是空的value。这就是说,若是在表中没有发现搜索键,或者若是发现了搜索键,但它是一个空的值,那么get()将返回null。若是有必要,用containKey()方法来区别这两种状况。       ide

一些资料建议,当须要同步时,用Hashtable,反之用HashMap。可是,由于在须要时,HashMap能够被同步,HashMap的功能比Hashtable的功能更多,并且它不是基于一个陈旧的类的,因此有人认为,在各类状况下,HashMap都优先于Hashtable。          函数

关于Properties     性能

有时侯,你可能想用一个hashtable来映射key的字符串到value的字符串。DOS、Windows和Unix中的环境字符串就有一些例子,如key的字符串PATH被映射到value的字符串C:\WINDOWS;C:\WINDOWS\SYSTEM。Hashtables是表示这些的一个简单的方法,但Java提供了另一种方法。        ui

Java.util.Properties类是Hashtable的一个子类,设计用于String keys和values。Properties对象的用法同Hashtable的用法相象,可是类增长了两个节省时间的方法,你应该知道。      

Store()方法把一个Properties对象的内容以一种可读的形式保存到一个文件中。Load()方法正好相反,用来读取文件,并设定Properties对象来包含keys和values。        

注意,由于Properties扩展了Hashtable,你能够用超类的put()方法来添加不是String对象的keys和values。这是不可取的。另外,若是你将store()用于一个不包含String对象的Properties对象,store()将失败。做为put()和get()的替代,你应该用setProperty()和getProperty(),它们用String参数。        

好了,我但愿你如今能够知道如何用hashtables来加速你的处理了。  

    

咱们再来看下JavaAPI中是怎么说的。 

java.util
类 HashMap<K,V>

java.lang.Object
  继承者 java.util.AbstractMap<K,V>
      继承者 java.util.HashMap<K,V>

类型参数:
K - 此映射所维护的键的类型
V - 所映射值的类型

全部已实现的接口:
Serializable, Cloneable, Map<K,V>

直接已知子类:
LinkedHashMap, PrinterStateReasons


public class HashMap<K,V>
    
    
    
    
extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable
 

基于哈希表的 Map 接口的实现。此实现提供全部可选的映射操做,并容许使用 null 值和 null 键。(除了非同步和容许使用 null 以外,HashMap 类与 Hashtable 大体相同。)此类不保证映射的顺序,特别是它不保证该顺序恒久不变。

此实现假定哈希函数将元素适当地分布在各桶之间,可为基本操做(getput)提供稳定的性能。迭代 collection 视图所需的时间与 HashMap 实例的“容量”(桶的数量)及其大小(键-值映射关系数)成比例。因此,若是迭代性能很重要,则不要将初始容量设置得过高(或将加载因子设置得过低)。

HashMap 的实例有两个参数影响其性能:初始容量加载因子容量 是哈希表中桶的数量,初始容量只是哈希表在建立时的容量。加载因子 是哈希表在其容量自动增长以前能够达到多满的一种尺度。当哈希表中的条目数超出了加载因子与当前容量的乘积时,则要对该哈希表进行 rehash 操做(即重建内部数据结构),从而哈希表将具备大约两倍的桶数。

一般,默认加载因子 (.75) 在时间和空间成本上寻求一种折衷。加载因子太高虽然减小了空间开销,但同时也增长了查询成本(在大多数 HashMap 类的操做中,包括 getput 操做,都反映了这一点)。在设置初始容量时应该考虑到映射中所需的条目数及其加载因子,以便最大限度地减小 rehash 操做次数。若是初始容量大于最大条目数除以加载因子,则不会发生 rehash 操做。

若是不少映射关系要存储在 HashMap 实例中,则相对于按需执行自动的 rehash 操做以增大表的容量来讲,使用足够大的初始容量建立它将使得映射关系能更有效地存储。

注意,此实现不是同步的。若是多个线程同时访问一个哈希映射,而其中至少一个线程从结构上修改了该映射,则它必须 保持外部同步。(结构上的修改是指添加或删除一个或多个映射关系的任何操做;仅改变与实例已经包含的键关联的值不是结构上的修改。)这通常经过对天然封装该映射的对象进行同步操做来完成。若是不存在这样的对象,则应该使用 Collections.synchronizedMap 方法来“包装”该映射。最好在建立时完成这一操做,以防止对映射进行意外的非同步访问,以下所示:

   Map m = Collections.synchronizedMap(new HashMap(...));

由全部此类的“collection 视图方法”所返回的迭代器都是快速失败 的:在迭代器建立以后,若是从结构上对映射进行修改,除非经过迭代器自己的 remove 方法,其余任什么时候间任何方式的修改,迭代器都将抛出 ConcurrentModificationException。所以,面对并发的修改,迭代器很快就会彻底失败,而不冒在未来不肯定的时间发生任意不肯定行为的风险。

注意,迭代器的快速失败行为不能获得保证,通常来讲,存在非同步的并发修改时,不可能做出任何坚定的保证。快速失败迭代器尽最大努力抛出 ConcurrentModificationException。所以,编写依赖于此异常的程序的作法是错误的,正确作法是:迭代器的快速失败行为应该仅用于检测程序错误。

此类是 Java Collections Framework 的成员。



java.util
类 Hashtable<K,V>

java.lang.Object
  继承者 java.util.Dictionary<K,V>
      继承者 java.util.Hashtable<K,V>

全部已实现的接口:
Serializable, Cloneable, Map<K,V>

直接已知子类:
Properties, UIDefaults


public class Hashtable<K,V>
    
    
    
    
extends Dictionary<K,V>
implements Map<K,V>, Cloneable, Serializable
 

此类实现一个哈希表,该哈希表将键映射到相应的值。任何非 null 对象均可以用做键或值。

为了成功地在哈希表中存储和获取对象,用做键的对象必须实现 hashCode 方法和 equals 方法。

Hashtable 的实例有两个参数影响其性能:初始容量加载因子容量 是哈希表中 的数量,初始容量 就是哈希表建立时的容量。注意,哈希表的状态为 open:在发生“哈希冲突”的状况下,单个桶会存储多个条目,这些条目必须按顺序搜索。加载因子 是对哈希表在其容量自动增长以前能够达到多满的一个尺度。初始容量和加载因子这两个参数只是对该实现的提示。关于什么时候以及是否调用 rehash 方法的具体细节则依赖于该实现。

一般,默认加载因子(.75)在时间和空间成本上寻求一种折衷。加载因子太高虽然减小了空间开销,但同时也增长了查找某个条目的时间(在大多数 Hashtable 操做中,包括 getput 操做,都反映了这一点)。

初始容量主要控制空间消耗与执行 rehash 操做所须要的时间损耗之间的平衡。若是初始容量大于 Hashtable 所包含的最大条目数除以加载因子,则永远 不会发生 rehash 操做。可是,将初始容量设置过高可能会浪费空间。

若是不少条目要存储在一个 Hashtable 中,那么与根据须要执行自动 rehashing 操做来增大表的容量的作法相比,使用足够大的初始容量建立哈希表或许能够更有效地插入条目。

下面这个示例建立了一个数字的哈希表。它将数字的名称用做键:

   Hashtable<String, Integer> numbers      = new Hashtable<String, Integer>();    numbers.put("one", 1);    numbers.put("two", 2);    numbers.put("three", 3);

要获取一个数字,可使用如下代码:

   }Integer n = numbers.get("two");      if (n != null) {          System.out.println("two = " + n);      }

由全部类的“collection 视图方法”返回的 collection 的 iterator 方法返回的迭代器都是快速失败 的:在建立 Iterator 以后,若是从结构上对 Hashtable 进行修改,除非经过 Iterator 自身的 remove 方法,不然在任什么时候间以任何方式对其进行修改,Iterator 都将抛出ConcurrentModificationException。所以,面对并发的修改,Iterator 很快就会彻底失败,而不冒在未来某个不肯定的时间发生任意不肯定行为的风险。由 Hashtable 的键和元素方法返回的 Enumeration 是快速失败的。

注意,迭代器的快速失败行为没法获得保证,由于通常来讲,不可能对是否出现不一样步并发修改作出任何硬性保证。快速失败迭代器会尽最大努力抛出 ConcurrentModificationException。所以,为提升这类迭代器的正确性而编写一个依赖于此异常的程序是错误作法:迭代器的快速失败行为应该仅用于检测程序错误。

从Java 2 平台 v1.2起,此类就被改进以实现 Map 接口,使它成为 Java Collections Framework 中的一个成员。不像新的 collection 实现,Hashtable 是同步的

 

StringBuilder与StringBuffer的区别

1. 在执行速度方面的比较:StringBuilder > StringBuffer

2. StringBuffer与StringBuilder,他们是字符串变量,是可改变的对象,每当咱们用它们对字符串作操做时,其实是在一个对象上操做的,不像String同样建立一些对象进行操做,因此速度就快了。

3. StringBuilder:线程非安全的   StringBuffer:线程安全的 当咱们在字符串缓冲去被多个线程使用是,JVM不能保证StringBuilder的操做是安全的,虽然他的速度最快,可是能够保证StringBuffer是能够正确操做的。固然大多数状况下就是咱们是在单线程下进行的操做,因此大多数状况下是建议用StringBuilder而不用StringBuffer的,就是速度的缘由。

对于三者使用的总结:

1.若是要操做少许的数据用 = String       

2.单线程操做字符串缓冲区 下操做大量数据 = StringBuilder       

3.多线程操做字符串缓冲区 下操做大量数据 = StringBuffer

相关文章
相关标签/搜索