51.HashMap的实现原理java
HashMap的主干是一个Entry数组。 Entry是HashMap的基本组成单元, 每个Entry包含一个key-value键值对。 HashMap基于hashing原理, 咱们经过put()和get()方法储存和获取对象。 当咱们将键值对传递给put()方法时, 它调用键对象的hashCode()方法 来计算hashcode, 让后找到bucket位置来储存值对象。 当获取对象时, 经过键对象的equals()方法 找到正确的键值对, 而后返回值对象。 HashMap使用链表来解决碰撞问题, 当发生碰撞了, 对象将会储存在链表的下一个节点中。 HashMap在每一个链表节点中储存键值对对象。 当两个不一样的键对象的hashcode 相同时会发生什么? 它们会储存在同一个bucket位置的链表中。 键对象的equals()方法用来找到键值对。 由于HashMap的好处很是多, 我曾经在电子商务的应用中使用HashMap做为缓存。 由于金融领域很是多的运用Java, 也出于性能的考虑, 咱们会常常用到HashMap和ConcurrentHashMap。 HashMap由数组+链表组成的, 数组是HashMap的主体, 链表则是主要为了解决哈希冲突而存在的, 若是定位到的数组位置不含链表 当前entry的next指向null, 那么对于查找, 添加等操做很快, 仅需一次寻址便可; 若是定位到的数组包含链表, 对于添加操做, 其时间复杂度为O(n), 首先遍历链表, 存在即覆盖, 不然新增; 对于查找操做来说, 仍需遍历链表, 而后经过key对象的equals方法逐一比对查找。 因此,性能考虑,HashMap中的链表出现越少, 性能才会越好。
52.List、Set、Map之间的区别web
List、Set是实现了Collection接口的子接口; 而Map是另外一个集合接口。 1元素重复性: List容许有重复的元素。 任何数量的重复元素 均可以在不影响现有重复元素的值 及其索引的状况下插入到List集合中; Set集合不容许元素重复。 Set以及全部实现了Set接口的类 都不容许重复值的插入, 若屡次插入同一个元素时, 在该集合中只显示一个; Map以键值对的形式对元素进行存储。 Map不容许有重复键, 但容许有不一样键对应的重复的值; 2.元素的有序性: List及其全部实现类保持了 每一个元素的插入顺序; Set中的元素都是无序的; 可是某些Set的实现类 以某种殊形式对其中的元素进行排序, 如:LinkedHashSet按照元素的 插入顺序进行排序; Map跟Set同样对元素进行无序存储, 但其某些实现类对元素进行了排序。 如:TreeMap根据键对其中的元素进行升序排序; 3.元素是否为空值: 1.List容许任意数量的空值; 2.Set最多容许一个空值的出现; 当向Set集合中添加多个null值时, 在该Set集合中只会显示一个null元素 3.Map只容许出现一个空键, 但容许出现任意数量的空值; --------------------------------- 总结: List中的元素: 有序、可重复、可为空; Set中的元素: 无序、不重复、只有一个空元素; Map中的元素: 无序、键不重,值可重、可一个空键、多可空值;
53.HashMap 的长度为何是2的幂次方算法
1.减少哈希冲突几率 假如当前Entry数组长度为len, 插入节点时, 须要对key的hashcode进行二次哈希, 而后跟len-1相与 获得的值必定小于len,避免数组越界 若是len是2的N次方, 那么len-1的后N位二进制必定是全1 假设有两个key, 他们的hashcode不一样, 分别为code1和code2 code1和code2分别与一个后N位全1的二进制相与, 结果必定也不一样 可是,若是code1和code2分别 与一个后N位非全1的二进制相与, 结果有可能相同 也就是说, 若是len是2^N, 不一样hashcode的key 计算出来的数组下标必定不一样; 不然, 不一样hashcode的key 计算出来的数组下标必定相同。 因此HashMap长度为全1, 能够减少哈希冲突几率。 ---------------------- 2.提升计算下标的效率 若是len的二进制后n位非全1, 与len-1相与时, 0与1相与须要取反。 若是len的二进制后n位全1, 彻底不须要取反。 若是len为2^N, 那么与len-1相与, 跟取余len等价, 而与运算效率高于取余。 若是len不是2^N, 与len-1相与, 跟取余len不等价。
54.集合框架中的泛型有什么优势?编程
首先, 了解一下Java关于泛型的概念。 泛型,在C++中被称为模板, 就是一种抽象的编程方式。 当咱们定义类和方法的时候, 能够用一种通用的方式进行定义, 而没必要写出具体的类, 这些未知的东西会在真正使用的时候在肯定。 对于集合类来讲, 它们能够存放各类类型的元素。 若是在存放以前, 就能肯定元素的类型, 那么就能够更加直观, 也让代码更加简洁。 说明: java的泛型是停留在编译层的, 也就是说JVM在对待泛型数据的时候, 依然会把它们当作是Object类型, 只不过在使用这些元素的时候, JVM会自动帮助咱们进行相应的类型转换。 总结: 集合使用泛型以后, 能够达到元素类型明确的目的, 避免了手动类型转换的过程, 同时,也让咱们更加明确 容器保存的是什么类型的数据。
55.咱们可否使用任何类做为Map的key?数组
一、能够 可是作为key的数据有以下要求: 二、首先, 要求明确一点Map集合存储数据的 主要目的是为了查找 而List集合是为了输出 三、既然是查找那么就要涉及到对象比较 咱们说了若是要进行对象比较 就必须覆写Object类中的equals()、hasCode() 至少覆写equals()方法 简单理解: 本身定义的类若是要想实现对象比较 就必须至少覆写equals()方法 四、或则这么说只要是本身定义的类 要想将其做为key 就必须覆写equals()方法 五、实际工做中 key的类型必定是String型 (95%通用) 其他的5%是没事找事的 六、按标准开发、你会感到事半功倍, 不要没事给本身找事, 固然求知精神是值得确定的。
56.Map接口提供了哪些不一样的集合视图?缓存
Map接口提供了三个集合视图: 1.Set keyset(): 返回map中包含的全部key的一个Set视图。 集合是受map支持的, map的变化会在集合中反映出来, 反之亦然。 当一个迭代器正在遍历一个集合时, 若map被修改了(除迭代器自身的移除操做之外), 迭代器的结果会变为未定义。 集合支持经过 Iterator的Remove、 Set.remove、 removeAll、 retainAll和clear操做进行元素移除, 从map中移除对应的映射。 它不支持add和addAll操做。 2.Collection values(): 返回一个map中包含的 全部value的一个Collection视图。 这个collection受map支持的, map的变化会在collection中反映出来, 反之亦然。 当一个迭代器正在遍历一个collection时, 若map被修改了(除迭代器自身的移除操做之外), 迭代器的结果会变为未定义。 集合支持经过 Iterator的Remove、 Set.remove、 removeAll、 retainAll和clear操做进行元素移除, 从map中移除对应的映射。 它不支持add和addAll操做。 3.Set> entrySet(): 返回一个map钟包含的 全部映射的一个集合视图。 这个集合受map支持的, map的变化会在collection中反映出来, 反之亦然。 当一个迭代器正在遍历一个集合时, 若map被修改了 除迭代器自身的移除操做, 以及对迭代器返回的entry进行setValue外, 迭代器的结果会变为未定义。 集合支持经过 Iterator的Remove、 Set.remove、 removeAll、 retainAll和clear操做进行元素移除, 从map中移除对应的映射。 它不支持add和addAll操做。
57.哪些集合类是线程安全的?安全
在集合框架中,有些类是线程安全的, 这些都是jdk1.1中的出现的。 在jdk1.2以后, 就出现许许多多非线程安全的类。 下面是这些线程安全的同步的类: vector: 就比arraylist多了个同步化机制(线程安全), 由于效率较低, 如今已经不太建议使用。 在web应用中, 特别是前台页面, 每每效率(页面响应速度)是优先考虑的。 statck:堆栈类,先进后出 hashtable:就比hashmap多了个线程安全 enumeration:枚举,至关于迭代器 除了这些以外, 其余的都是非线程安全的类和接口。 线程安全的类其方法是同步的, 每次只能一个访问。 是重量级对象, 效率较低。
58.队列和栈是什么,列出它们的区别?数据结构
队列(Queue): 是限定只能在表的一端进行 插入和在另外一端进行删除操做的线性表; 栈(Stack): 是限定只能在表的一端 进行插入和删除操做的线性表。 区别以下: 1、规则不一样 1. 队列:先进先出(First In First Out)FIFO 2. 栈:先进后出(First In Last Out )FILO 2、对插入和删除操做的限定不一样 1. 队列:只能在表的一端进行插入, 并在表的另外一端进行删除; 2. 栈:只能在表的一端插入和删除。 3、遍历数据速度不一样 1. 队列:基于地址指针进行遍历, 并且能够从头部或者尾部进行遍历, 但不能同时遍历, 无需开辟空间, 由于在遍历的过程当中不影响数据结构, 因此遍历速度要快; 2. 栈:只能从顶部取数据, 也就是说最早进入栈底的, 须要遍历整个栈才能取出来, 并且在遍历数据的同时须要 为数据开辟临时空间, 保持数据在遍历前的一致性。
59.哪个List实现了最快插入?并发
LinkedList和ArrayList 是另个不一样变量列表的实现。 ArrayList的优点在于动态的增加数组, 很是适合初始时总长度未知的状况下使用。 LinkedList的优点在于在中间位置插入和删除操做, 速度是最快的。 LinkedList实现了List接口, 容许null元素。 此外LinkedList提供额外的 get,remove,insert方法 在LinkedList的首部或尾部。 这些操做使LinkedList可被 用做堆栈(stack), 队列(queue) 或双向队列(deque)。 ArrayList实现了可变大小的数组。 它容许全部元素, 包括null。 每一个ArrayList实例都有一个容量(Capacity), 即用于存储元素的数组的大小。 这个容量可随着不断添加新元素而自动增长, 可是增加算法并无定义。 当须要插入大量元素时, 在插入前能够调用ensureCapacity方法来 增长ArrayList的容量以提升插入效率。
60.何时使用ConcurrentHashMap?框架
快速失败的Java迭代器 可能会引起ConcurrentModifcationException 在底层集合迭代过程当中被修改。 故障安全做为发生在实例中的一个副本 迭代是不会抛出任何异常的。 快速失败的故障安全范例定义了 当遭遇故障时系统是如何反应的。 例如,用于失败的快速迭代器ArrayList 和用于故障安全的迭代器ConcurrentHashMap。 ConcurrentHashMap被做为 故障安全迭代器的一个实例, 它容许完整的并发检索和更新。 当有大量的并发更新时, ConcurrentHashMap此时能够被使用。 这很是相似于Hashtable, 但ConcurrentHashMap不锁定 整个表来提供并发, 因此从这点上ConcurrentHashMap的性能 彷佛更好一些。 因此当有大量更新时 ConcurrentHashMap应该被使用。