您的位置:首页 > 职场人生

面试中集合相关问题(补充ing.....)

2017-11-15 17:25 375 查看
面试中集合相关问题(补充ing.....)

一、HashMap和Hashtable的区别

HashMap和Hashtable都实现了Map接口,但决定用哪一个之前先要弄清楚它们之间的分别。主要的区别有:线程安全性,同步(synchronization),以及速度。


1.区别

  1).HashMap几乎可以等价于Hashtable,除了HashMap是非synchronized的,并可以接受null(HashMap可以接受为null的键值(key)和值(value),而Hashtable则不行)。

  2).HashMap是非synchronized,而Hashtable是synchronized,这意味着Hashtable是线程安全的,多个线程可以共享一个Hashtable;而如果没有正确的同步的话,多个线程是不能共享HashMap的。Java
5提供了ConcurrentHashMap,它是HashTable的替代,比HashTable的扩展性更好。

  3).另一个区别是HashMap的迭代器(Iterator)是fail-fast迭代器,而Hashtable的enumerator迭代器不是fail-fast的。所以当有其它线程改变了HashMap的结构(增加或者移除元素),将会抛出ConcurrentModificationException,但迭代器本身的remove()方法移除元素则不会抛出ConcurrentModificationException异常。但这并不是一个一定发生的行为,要看JVM。这条同样也是Enumeration和Iterator的区别。

  4).由于Hashtable是线程安全的也是synchronized,所以在单线程环境下它比HashMap要慢。如果你不需要同步,只需要单一线程,那么使用HashMap性能要好过Hashtable。

  5).HashMap不能保证随着时间的推移Map中的元素次序是不变的。

2.要注意的一些重要术语:

  1).sychronized意味着在一次仅有一个线程能够更改Hashtable。就是说任何线程要更新Hashtable时要首先获得同步锁,其它线程要等到同步锁被释放之后才能再次获得同步锁更新Hashtable。

  2). Fail-safe和iterator迭代器相关。如果某个集合对象创建了Iterator或者ListIterator,然后其它的线程试图“结构上”更改集合对象,将会抛出ConcurrentModificationException异常。但其它线程可以通过set()方法更改集合对象是允许的,因为这并没有从“结构上”更改集合。但是假如已经从结构上进行了更改,再调用set()方法,将会抛出IllegalArgumentException异常。

  3).结构上的更改指的是删除或者插入一个元素,这样会影响到map的结构。

  我们能否让HashMap同步?

  HashMap可以通过下面的语句进行同步:
  Map m = Collections.synchronizeMap(hashMap);

3.结论

  Hashtable和HashMap有几个主要的不同:线程安全以及速度。仅在你需要完全的线程安全的时候使用Hashtable,而如果你使用Java 5或以上的话,请使用ConcurrentHashMap吧。


二、HashMap和LinkedHashMap的区别

1. LinkedHashMap概述

  1).LinkedHashMap是HashMap的一个子类,它保留插入的顺序,如果需要输出的顺序和输入时的相同,那么就选用LinkedHashMap。

  2).LinkedHashMap是Map接口的哈希表和链接列表实现,具有可预知的迭代顺序。此实现提供所有可选的映射操作,并允许使用null值和null键。此类不保证映射的顺序,特别是它不保证该顺序恒久不变。

  3).LinkedHashMap实现与HashMap的不同之处在于,后者维护着一个运行于所有条目的双重链接列表。此链接列表定义了迭代顺序,该迭代顺序可以是插入顺序或者是访问顺序。

  注意,此实现不是同步的。如果多个线程同时访问链接的哈希映射,而其中至少一个线程从结构上修改了该映射,则它必须保持外部同步。

  根据链表中元素的顺序可以分为:按插入顺序的链表,和按访问顺序(调用get方法)的链表。

  默认是按插入顺序排序,如果指定按访问顺序排序,那么调用get方法后,会将这次访问的元素移至链表尾部,不断访问可以形成按访问顺序排序的链表。 可以重写removeEldestEntry方法返回true值指定插入元素时移除最老的元素。

  

2. LinkedHashMap的实现

  对于LinkedHashMap而言,它继承与HashMap、底层使用哈希表与双向链表来保存所有元素。其基本操作与父类HashMap相似,它通过重写父类相关的方法,来实现自己的链接列表特性。

3.总结

  HashMap和LinkedHashMap区别在于HashMap是无序的,LinkedHashMap是有序的。在使用HashMap时,要根据实际情况选择最优的解决方案,降低性能和空间上的浪费。

三、HashMap、SynchronizedMap、ConcurrentHashMap底层实现和区别

1.HashMap是线程不安全的

  使用transient数组对象table保存键值对(静态的内部类Entry)链表的集合。

  既然使用数组就会涉及到扩容,默认容量大小为16,扩容因子为0.75,自定义容量大小也只能是大于输入值的最小2的n次方,以便于提高内部操作效率。

  使用散列表的方式来高效的存取数据,根据键Key的HashCode计算出的hash值,存储到数组相应下标的链表中。

 

2.SynchronizedMap是线程安全的

  使用装饰器模式对普通的map接口的实现类实例进行装饰  

  SynchronizedMap持有map接口的实现类实例,并对其方法添加synchronized关键字,以达到线程安全的目的。

  虽然HashTable与SynchronizedMap都使用synchronized同步锁实现线程安全。

  但他们的意义不同,hashtable是独立实现功能的一个类,关注于实现内部数据结构等细节功能;

  而SynchronizedMap是一个装饰map接口的实现类实例的装饰者,他关注于装饰实例的方法到同步代码块中。

 

3.ConcurrenthasHmap是线程安全的

  使用final数组sengments对象保存分段的键值对集合(继承于ReentrantLock的static
final修饰的内部类Segment)集合。

  使用数组仍然会涉及到扩容,默认分段等级为16,容量大小为16,每个子容器大小为容量大小除以分段等级,扩容因子为0.75。

  Segment是一个线程安全的键值对集合,使用了ReentrantLock解决并发问题,并且ConcurrentHashMap使用了分段的技术提高了N(分段的段数)倍效率。

  ConcurrentHashMap散列了两次,第一次散列成多个的线程安全的键值对集合,第二次散列成多个键值对链表。

  两次散列的hash值都是根据键Key计算出来的,所以两次散列计算hash值方法必须是不相同。

四、ArrayList、LinkedList、Vector的区别


1.LinkedList类

  LinkedList实现了List接口,允许null元素。此外LinkedList提供额外的get,remove,insert方法在LinkedList的首部或尾部。这些操作使LinkedList可被用作堆栈  (stack),队列(queue)或双向队列(deque)。
  注意LinkedList没有同步方法。如果多个线程同时访问一个List,则必须自己实现访问同步。一种解决方法是在创建List时构造一个同步的List:
    List list = Collections.synchronizedList(new LinkedList(...));

2.ArrayList类

  ArrayList实现了可变大小的数组。它允许所有元素,包括null。ArrayList没有同步
  size,isEmpty,get,set方法运行时间为常数。但是add方法开销为分摊的常数,添加n个元素需要O(n)的时间。其他的方法运行时间为线性。
  每个ArrayList实例都有一个容量(Capacity),即用于存储元素的数组的大小。这个容量可随着不断添加新元素而自动增加,但是增长算法并没有定义。当需要插入大量元素时,在插入前可以调用ensureCapacity方法来增加ArrayList的容量以提高插入效率。
  和LinkedList一样,ArrayList也是非同步的(unsynchronized)。

3.Vector类

  Vector非常类似ArrayList,但是Vector是同步的。由Vector创建的Iterator,虽然和ArrayList创建的Iterator是同一接口,但是,因为Vector是同步的,当一个Iterator被创建而且正在被使用,另一个线程改变了Vector的状态(例如,添加或删除了一些元素),这时调用Iterator的方法时将抛出ConcurrentModificationException,因此必须捕获该异常。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: