BAT面试必备——Java 集合类

本文首发于个人我的博客:尾尾部落html

来源:http://www.runoob.com/java/java-collections.html

来源:https://www.cnblogs.com/jing99/p/7057245.html

1. Iterator接口

Iterator接口,这是一个用于遍历集合中元素的接口,主要包含hashNext(),next(),remove()三种方法。它的一个子接口LinkedIterator在它的基础上又添加了三种方法,分别是add(),previous(),hasPrevious()。也就是说若是是先Iterator接口,那么在遍历集合中元素的时候,只能日后遍历,被遍历后的元素不会在遍历到,一般无序集合实现的都是这个接口,好比HashSet,HashMap;而那些元素有序的集合,实现的通常都是LinkedIterator接口,实现这个接口的集合能够双向遍历,既能够经过next()访问下一个元素,又能够经过previous()访问前一个元素,好比ArrayList。java

2. List

List是元素有序而且能够重复的集合。 List的主要实现:ArrayList, LinkedList, Vector。 面试

2. ArrayList、LinkedList、Vector 的区别

ArrayList LinkedList Vector
底层实现 数组 双向循环链表 数组
同步性及效率 不一样步,非线程安全,效率高 不一样步,非线程安全,效率高 同步,线程安全,效率低
特色 查询快,增删慢 查询慢,增删快 查询快,增删慢
默认容量 10 / 10
扩容机制 int newCapacity = oldCapacity + (oldCapacity >> 1); //1.5 / 2 倍

总结算法

  • ArrayList 和 Vector 基于数组实现,对于随机访问get和set,ArrayList优于LinkedList,由于LinkedList要移动指针。
  • LinkedList 不会出现扩容的问题,因此比较适合随机位置增、删。可是其基于链表实现,因此在定位时须要线性扫描,效率比较低。
  • 当操做是在一列数据的后面添加数据而不是在前面或中间,而且须要随机地访问其中的元素时,使用ArrayList会提供比较好的性能;
  • 当你的操做是在一列数据的前面或中间添加或删除数据,而且按照顺序访问其中的元素时,就应该使用LinkedList了。

3. Set

Set集合中的对象不按特定的方式排序(存入和取出的顺序不必定一致),而且没有重复对象。 Set的主要实现类:HashSet, TreeSet。 数组

HashSet TreeSet LinkedHashSet
底层实现 HashMap 红黑树 LinkedHashMap
重复性 不容许重复 不容许重复 不容许重复
有/无序 无序 有序,支持两种排序方式,天然排序和定制排序,其中天然排序为默认的排序方式。 有序,以元素插入的顺序来维护集合的连接表
时间复杂度 add(),remove(),contains()方法的时间复杂度是O(1) add(),remove(),contains()方法的时间复杂度是O(logn) LinkedHashSet在迭代访问Set中的所有元素时,性能比HashSet好,可是插入时性能稍微逊色于HashSet,时间复杂度是 O(1)。
同步性 不一样步,线程不安全 不一样步,线程不安全 不一样步,线程不安全
null值 容许null值 不支持null值,会抛出 java.lang.NullPointerException 异常。由于TreeSet应用 compareTo() 方法于各个元素来比较他们,当比较null值时会抛出 NullPointerException异常。 容许null值
比较 equals() compareTo() equals()

HashSet如何检查重复

当你把对象加入HashSet时,HashSet会先计算对象的hashcode值来判断对象加入的位置,同时也会与其余加入的对象的hashcode值做比较,若是没有相符的hashcode,HashSet会假设对象没有重复出现。可是若是发现有相同hashcode值的对象,这时会调用equals()方法来检查hashcode相等的对象是否真的相同。若是二者相同,HashSet就不会让加入操做成功。 hashCode()与equals()的相关规定:安全

  • 若是两个对象相等,则hashcode必定也是相同的
  • 两个对象相等,对两个equals方法返回true
  • 两个对象有相同的hashcode值,它们也不必定是相等的
  • 综上,equals方法被覆盖过,则hashCode方法也必须被覆盖 hashCode()的默认行为是对堆上的对象产生独特值。若是没有重写hashCode(),则该class的两个对象不管如何都不会相等(即便这两个对象指向相同的数据)。

总结: HashSet是一个通用功能的Set,而LinkedHashSet 提供元素插入顺序保证,TreeSet是一个SortedSet实现,由Comparator 或者 Comparable指定的元素顺序存储元素。微信

4. Map

Map 是一种把键对象和值对象映射的集合,它的每个元素都包含一对键对象和值对象。 Map没有继承于Collection接口从Map集合中检索元素时,只要给出键对象,就会返回对应的值对象。 Map 的经常使用实现类:HashMap、TreeMap、HashTable、LinkedHashMap、ConcurrentHashMap数据结构

HashMap HashTable
底层实现 数组+链表 数组+链表
同步性 线程不一样步 同步
null值 容许 key 和 Vale 是 null,可是只容许一个 key 为 null,且这个元素存放在哈希表 0 角标位置 不容许key、value 是 null
hash 使用hash(Object key)扰动函数对 key 的 hashCode 进行扰动后做为 hash 值 直接使用 key 的 hashCode() 返回值做为 hash 值
容量 容量为 2^4 且容量必定是 2^n 默认容量是11,不必定是 2^n
扩容 两倍,且哈希桶的下标使用 &运算代替了取模 2倍+1,取哈希桶下标是直接用模运算

几个问题:

1. HashMap 的工做原理? 经过hash的方法,经过put和get存储和获取对象。存储对象时,咱们将K/V传给put方法时,它调用hashCode计算hash从而获得bucket位置,进一步存储,HashMap会根据当前bucket的占用状况自动调整容量(超过Load Facotr则resize为原来的2倍)。获取对象时,咱们将K传给get,它调用hashCode计算hash从而获得bucket位置,并进一步调用equals()方法肯定键值对。若是发生碰撞的时候,Hashmap经过链表将产生碰撞冲突的元素组织起来,在Java 8中,若是一个bucket中碰撞冲突的元素超过某个限制(默认是8),则使用红黑树来替换链表,从而提升效率。 2.get和put的原理吗?equals()和hashCode()的都有什么做用? 经过对key的hashCode()进行hashing,并计算下标( n-1 & hash),从而得到buckets的位置。若是产生碰撞,则利用key.equals()方法去链表或树中去查找对应的节点 3. HashMap 的长度为何是2的幂次方? 为了能让 HashMap 存取高效,尽可能较少碰撞,也就是要尽可能把数据分配均匀,每一个链表/红黑树长度大体相同。这个实现就是把数据存到哪一个链表/红黑树中的算法。多线程

HashMap 和 LinkedHashMap 的区别

  • LinkedHashMap 拥有与 HashMap 相同的底层哈希表结构,即数组 + 单链表 + 红黑树,也拥有相同的扩容机制。
  • LinkedHashMap 相比 HashMap 的拉链式存储结构,内部额外经过 Entry 维护了一个双向链表。
  • HashMap 元素的遍历顺序不必定与元素的插入顺序相同,而 LinkedHashMap 则经过遍历双向链表来获取元素,因此遍历顺序在必定条件下等于插入顺序。
  • LinkedHashMap 能够经过构造参数 accessOrder 来指定双向链表是否在元素被访问后改变其在双向链表中的位置。

HashMap & TreeMap 的区别

HashMap实现了Map接口,不保障元素顺序。 TreeMap实现了SortedMap接口,是一个有序的Map。内部采用红黑树实现,红黑树是一种维护有序数据的高效数据结构并发

ConcurrentHashMap 和 Hashtable 的区别

ConcurrentHashMap 和 Hashtable 的区别主要体如今实现线程安全的方式上不一样。 底层数据结构: JDK1.7的 ConcurrentHashMap 底层采用 分段的数组+链表 实现,JDK1.8 采用的数据结构跟HashMap1.8的结构同样,数组+链表/红黑二叉树。Hashtable 和 JDK1.8 以前的 HashMap 的底层数据结构相似都是采用 数组+链表 的形式,数组是 HashMap 的主体,链表则是主要为了解决哈希冲突而存在的; 实现线程安全的方式(重要): ① 在JDK1.7的时候,ConcurrentHashMap(分段锁) 对整个桶数组进行了分割分段(Segment),每一把锁只锁容器其中一部分数据,多线程访问容器里不一样数据段的数据,就不会存在锁竞争,提升并发访问率。(默认分配16个Segment,比Hashtable效率提升16倍。) 到了 JDK1.8 的时候已经摒弃了Segment的概念,而是直接用 Node 数组+链表+红黑树的数据结构来实现,并发控制使用 synchronized 和 CAS 来操做。(JDK1.6之后 对 synchronized锁作了不少优化) 整个看起来就像是优化过且线程安全的 HashMap,虽然在JDK1.8中还能看到 Segment 的数据结构,可是已经简化了属性,只是为了兼容旧版本;② Hashtable(同一把锁) :使用 synchronized 来保证线程安全,效率很是低下。当一个线程访问同步方法时,其余线程也访问同步方法,可能会进入阻塞或轮询状态,如使用 put 添加元素,另外一个线程不能使用 put 添加元素,也不能使用 get,竞争会愈来愈激烈效率越低。

JDK1.7的ConcurrentHashMap:
JDK1.8的ConcurrentHashMap(TreeBin: 红黑二叉树节点 Node: 链表节点):

参考

获取最新资讯,请关注微信公众号:南强说晚安

相关文章
相关标签/搜索