大田县建设资讯网站,办建筑资质证书要多少钱,世界工厂,房地产电商网站建设HashMap、LinkedHashMap、ConcurrentHashMap、ArrayList、LinkedList的底层实现。
HashMap相关问题
1、你用过HashMap吗#xff1f;什么是HashMap#xff1f;你为什么用到它#xff1f;用过#xff0c;HashMap是基于哈希表的Map接口的非同步实现#xff0c;
它允许null键…HashMap、LinkedHashMap、ConcurrentHashMap、ArrayList、LinkedList的底层实现。
HashMap相关问题
1、你用过HashMap吗什么是HashMap你为什么用到它用过HashMap是基于哈希表的Map接口的非同步实现
它允许null键和null值且HashMap依托于它的数据结构的设计
存储效率特别高这是我用它的原因2、你知道HashMap的工作原理吗你知道HashMap的get()方法
的工作原理吗上面两个问题属于同一答案的问题HashMap是基于hash算法实现的通过put(key,value)
存储对象到HashMap中也可以通过get(key)从HashMap中获取对象。
当我们使用put的时候首先HashMap会对key的hashCode()的值
进行hash计算根据hash值得到这个元素在数组中的位置
将元素存储在该位置的链表上。当我们使用get的时候
首先HashMap会对key的hashCode()的值进行hash计算
根据hash值得到这个元素在数组中的位置将元素从该位置上的链表中取出3、当两个对象的hashcode相同会发生什么hashcode相同说明两个对象HashMap数组的同一位置上
接着HashMap会遍历链表中的每个元素
通过key的equals方法来判断是否为同一个key
如果是同一个key则新的value会覆盖旧的value
并且返回旧的value。如果不是同一个key
则存储在该位置上的链表的链头4、如果两个键的hashcode相同你如何获取值对象遍历HashMap链表中的每个元素并对每个key进行hash计算
最后通过get方法获取其对应的值对象5、如果HashMap的大小超过了负载因子(load factor)定义的容量
怎么办负载因子默认是0.75HashMap超过了负载因子定义的容量
也就是说超过了HashMap的大小*负载因子这个值
那么HashMap将会创建为原来HashMap大小两倍的数组大小
作为自己新的容量这个过程叫resize或者rehash6、你了解重新调整HashMap大小存在什么问题吗当多线程的情况下可能产生条件竞争。当重新调整HashMap大小的时候
确实存在条件竞争如果两个线程都发现HashMap需要重新调整大小了
它们会同时试着调整大小。在调整大小的过程中
存储在链表中的元素的次序会反过来
因为移动到新的数组位置的时候
HashMap并不会将元素放在LinkedList的尾部而是放在头部
这是为了避免尾部遍历(tail traversing)。
如果条件竞争发生了那么就死循环了7、我们可以使用自定义的对象作为键吗可以只要它遵守了equals()和hashCode()方法的定义规则
并且当对象插入到Map中之后将不会再改变了。
如果这个自定义对象时不可变的那么它已经满足了作为键的条件
因为当它创建之后就已经不能改变了。HashSet与HashMap区别
HashMap实现了Map接口
HashSet实现了Set接口HashMap储存键值对
HashSet仅仅存储对象HashMap使用put()方法将元素放入map中
HashSet使用add()方法将元素放入set中HashMap中使用键对象来计算hashcode值
HashSet使用成员对象来计算hashcode值HashMap比较快因为是使用唯一的键来获取对象
HashSet较HashMap来说比较慢HashTable与HashMap的区别
Hashtable方法是同步的
HashMap方法是非同步的Hashtable基于Dictionary类
HashMap基于AbstractMap而AbstractMap基于Map接口的实现Hashtable中key和value都不允许为null遇到null
直接返回 NullPointerException
HashMap中key和value都允许为null遇到key为null的时候
调用putForNullKey方法进行处理而对value没有处理Hashtable中hash数组默认大小是11扩充方式是old*21
HashMap中hash数组的默认大小是16而且一定是2的指数LinkedHashMap的有序性
LinkedHashMap底层使用哈希表与双向链表来保存所有元素
它维护着一个运行于所有条目的双向链表
如果学过双向链表的同学会更好的理解它的源代码
此链表定义了迭代顺序该迭代顺序可以是插入顺序或者是访问顺序
1.按插入顺序的链表在LinkedHashMap调用get方法后
输出的顺序和输入时的相同这就是按插入顺序的链表
默认是按插入顺序排序2.按访问顺序的链表在LinkedHashMap调用get方法后
会将这次访问的元素移至链表尾部
不断访问可以形成按访问顺序排序的链表。简单的说
按最近最少访问的元素进行排序类似LRU算法我们可以通过例子来理解我们上面所说的LinkedHashMap的插入顺序和访问顺序
public static void main(String[] args) {MapString, String map new HashMapString, String();map.put(apple, 苹果);map.put(watermelon, 西瓜);map.put(banana, 香蕉);map.put(peach, 桃子);Iterator iter map.entrySet().iterator();while (iter.hasNext()) {Map.Entry entry (Map.Entry) iter.next();System.out.println(entry.getKey() entry.getValue());}
}上面是简单的HashMap代码通过控制台的输出我们可以看到HashMap是没有顺序的
banana香蕉 apple苹果 peach桃子 watermelon西瓜
我们现在将HashMap换成LinkedHashMap其他代码不变
MapString, String map new LinkedHashMapString, String();看一下控制台的输出
apple苹果 watermelon西瓜 banana香蕉 peach桃子
我们可以看到其输出顺序是完成按照插入顺序的也就是我们上面所说的保留了插入的顺序。下面我们修改一下代码通过访问顺序进行排序。
public static void main(String[] args) {MapString, String map new LinkedHashMapString, String(16,0.75f,true);map.put(apple, 苹果);map.put(watermelon, 西瓜);map.put(banana, 香蕉);map.put(peach, 桃子);map.get(banana);map.get(apple);Iterator iter map.entrySet().iterator();while (iter.hasNext()) {Map.Entry entry (Map.Entry) iter.next();System.out.println(entry.getKey() entry.getValue());}
}代码与之前的相比 1.替换了LinkedHashMap的构造函数使用三个参数的构造函数第三个参数传进true就是表明用访问顺序来排序默认是false即插入顺序 2.增加了两句LinkedHashMap的get方法来表示最近已经访问过这两个元素了
//修改的代码
MapString, String map new LinkedHashMapString, String(16,0.75f,true);
......
map.get(banana);
map.get(apple);
看一下控制台的输出结果
watermelon西瓜 peach桃子 banana香蕉 apple苹果
我们可以看到顺序是先从最少访问的元素开始遍历西瓜、桃子而香蕉、苹果是因为分别调用了get方法香蕉是最先访问的所以它的比苹果更少用一些。这也就是我们之前提到过的LinkedHashMap可以选择按照访问顺序进行排序
LinkedHashMap与HashMap的区别 LinkedHashMap有序的有插入顺序和访问顺序 HashMap无序的
LinkedHashMap内部维护着一个运行于所有条目的双向链表 HashMap内部维护着一个单链表
什么是ArrayList ArrayList可以理解为动态数组它的容量能动态增长该容量是指用来存储列表元素的数组的大小随着向ArrayList中不断添加元素其容量也自动增长 ArrayList允许包括null在内的所有元素 ArrayList是List接口的非同步实现 ArrayList是有序的
ArrayList实现了List接口、底层使用数组保存所有元素其操作基 本上是对数组的操作ArrayList继承了AbstractList抽象类它是一个数组队列提供了相关的添加、删除、修改、遍历等功能ArrayList实现了RandmoAccess接口即提供了随机访问功能RandmoAccess是java中用来被List实现为List提供快速访问功能的我们可以通过元素的序号快速获取元素对象这就是快速随机访问ArrayList实现了Cloneable接口即覆盖了函数clone()能被克隆
ArrayList实现了java.io.Serializable接口意味着ArrayList支持序列化什么是LinkedList LinkedList基于链表的List接口的非同步实现 LinkedList允许包括null在内的所有元素 LinkedList是有序的 LinkedList是fail-fast的 LinkedList与ArrayList的区别 LinkedList底层是双向链表 ArrayList底层是可变数组 LinkedList不允许随机访问 即查询效率低 ArrayList允许随机访问即查询效率高 LinkedList插入和删除效率快 ArrayList插入和删除效率低 解释一下
对于随机访问的两个方法get和setArrayList优于LinkedList因为LinkedList要移动指针 对于新增和删除两个方法add和removeLinedList比较占优势因为ArrayList要移动数据
什么是ConcurrentHashMap ConcurrentHashMap基于双数组和链表的Map接口的同步实现 ConcurrentHashMap中元素的key是唯一的、value值可重复 ConcurrentHashMap不允许使用null值和null键 ConcurrentHashMap是无序的 为什么使用ConcurrentHashMap 我们都知道HashMap是非线程安全的当我们只有一个线程在使用HashMap的时候自然不会有问题但如果涉及到多个线程并且有读有写的过程中HashMap就会fail-fast。要解决HashMap同步的问题我们的解决方案有 Hashtable Collections.synchronizedMap(hashMap) 这两种方式基本都是对整个hash表结构加上同步锁这样在锁表的期间别的线程就需要等待了无疑性能不高所以我们引入ConcurrentHashMap既能同步又能多线程访问 ConcurrentHashMap的数据结构 ConcurrentHashMap的数据结构为一个Segment数组Segment的数据结构为HashEntry的数组而HashEntry存的是我们的键值对可以构成链表。可以简单的理解为数组里装的是HashMap 从上面的结构我们可以了解到ConcurrentHashMap定位一个元素的过程需要进行两次Hash操作第一次Hash定位到Segment第二次Hash定位到元素所在的链表的头部因此这一种结构的带来的副作用是Hash的过程要比普通的HashMap要长但是带来的好处是写操作的时候可以只对元素所在的Segment进行加锁即可不会影响到其他的Segment。正是因为其内部的结构以及机制ConcurrentHashMap在并发访问的性能上要比Hashtable和同步包装之后的HashMap的性能提高很多。在理想状态下ConcurrentHashMap 可以支持 16 个线程执行并发写操作如果并发级别设置为 16及任意数量线程的读操作 什么是Vector Vector是基于可变数组的List接口的同步实现 Vector是有序的 Vector允许null键和null值 Vector已经不建议使用了 Vector实现了List接口、底层使用数组保存所有元素其操作基本上是对数组的操作 Vector继承了AbstractList抽象类它是一个数组队列提供了相关的添加、删除、修改、遍历等功能 Vector实现了RandmoAccess接口即提供了随机访问功能RandmoAccess是java中用来被List实现为List提供快速访问功能的我们可以通过元素的序号快速获取元素对象这就是快速随机访问 Vector实现了Cloneable接口即覆盖了函数clone()能被克隆 Vector实现了java.io.Serializable接口意味着ArrayList支持序列化
Vector和ArrayList的区别 Vector同步、线程安全的 ArrayList异步、线程不安全
Vector 需要额外开销来维持同步锁性能慢 ArrayList 性能快
Vector 可以使用Iterator、foreach、Enumeration输出 ArrayList 只能使用Iterator、foreach输出