文章目录
-
-
- 4.16 **以下结构中,插入性能最高的是**
- 4.17 **以下结构中,哪个最适合当作stack使用**
- 4.18 **Map的实现类中,哪些是有序的,哪些是无序的,有序的是如何保证其有序性,你觉得哪个有序性性能更高,你有没有更好或者更高效的实现方式**
- 4.19 **下面的代码在绝大部分时间内都运行得很正常,请问什么情况下会出现问题?根源在哪里**
- 4.20 **.TreeMap和TreeSet在排序时如何比较元素?Collections工具类中的sort()方法如何比较元素**
- 4.21 List如何剔除相同的对象
- 4.22 **Java.util.Map的实现类有**
- 4.23 **下列叙述中正确的是**
- 4.24 Java容器有哪些,哪些是同步容器?哪些是并发容器
- 4.25 ArrayList和LinkedList的插入和访问的时间复杂度
- 4.26 HashMap在什么情况下会扩容?哪些操作会触发扩容
- 4.27 HashMap中put方法的执行过程
- 4.28 HashMap检测到hash冲突后,将元素插入到链表的末尾还是开头
- 4.29 jdk1.8采用了红黑树,讲讲红黑树的特性,为什么人家一定要用红黑树而不是AVL
- 4.30 HashMap和HashTable底层实现有什么区别?HashTble和ConcurrentHashMap
- **HashTable**
- **HashMap**
- **ConcurrentHashMap**
- 4.31 快速失败和安全失败的区别是什么
-
4.16 以下结构中,插入性能最高的是
4.17 以下结构中,哪个最适合当作stack使用
4.18 Map的实现类中,哪些是有序的,哪些是无序的,有序的是如何保证其有序性,你觉得哪个有序性性能更高,你有没有更好或者更高效的实现方式
-
Map的实现类有HashMap,LinkedHashMap,TreeMap
-
HashMap是有无序的,LinkedHashMap和TreeMap都是有序的(LinkedHashMap记录了添加数据的顺序;TreeMap默认是自然升序)
-
LinkedHashMap底层存储结构是哈希表+链表,链表记录了添加数据的顺序
-
TreeMap底层存储结构是二叉树,二叉树的中序遍历保证了数据的有序性
-
LinkedHashMap有序性能比较高,因为底层数据存储结构采用的哈希表
4.19 下面的代码在绝大部分时间内都运行得很正常,请问什么情况下会出现问题?根源在哪里
import java.util.LinkedList;
public class Stack {
LinkedList list = new LinkedList();
public synchronized void push(Object x) {
synchronized (list) {
list.addLast(x);
notify();
}
}
public synchronized Object pop() throws Exception{
synchronized(list){
if(list.size()<=0){
wait();
}
return list.removeLast( );
}
}
}
将if(list.size())改为while(list.size())
4.20 .TreeMap和TreeSet在排序时如何比较元素?Collections工具类中的sort()方法如何比较元素
TreeSet要求存放的对象所属的类必须实现Comparable接口,该接口提供了比较元素的compareTo()方法,当插入元素时会 回调该方法比较元素的大小。TreeMap要求存放的键值对映射的键必须实现Comparable接口从而根据键对元素进行排序。Collections 工具类的sort方法有两种重载的形式,第一种要求传入的待排序容器中存放的对象比较实现Comparable接口以实现元素的比较;第二种不强制性的要求容器中的元素必须可比较,但是要求传入第二个参数,参数是Comparator接口的子类型(需要重写compare方法实现元素的比较),相当于一个临时定义的排序规则,其实就是是通过接口注入比较元素大小的算法,也是对回调模式的应用。
4.21 List如何剔除相同的对象
public class Test {
public static void main(String[] args) {
List<String> li1 = new ArrayList<String>();
li1.add("8");
li1.add("8");
li1.add("9");
li1.add("9");
li1.add("0");
System.out.println(li1);
//方法:将List中数据取出来来存到Set中
HashSet<String> set = new HashSet<String>();
for(int i=0;i<li1.size();i++){
set.add(li1.get(i));
}
System.out.println(set);
}
}
4.22 Java.util.Map的实现类有
1、HashMap
2、Hashtable
3、LinkedHashMap
4、TreeMap
4.23 下列叙述中正确的是
4.24 Java容器有哪些,哪些是同步容器?哪些是并发容器
同步容器:指的是线程安全的,一般都是使用了synchronized关键字,虽然保证了数据的一致性,但并发性却很差
- Vactor
- HashTable
- Stack
- Collections.synchronized()
并发容器:多线程环境下效率依然很高,减少锁的使用
- CopyOnWrieArrayList
- CopyOnWriteArraySet
- ConcurrentHashMap
- ArrayBlockingQueue
- LinkedBlockingQueue
4.25 ArrayList和LinkedList的插入和访问的时间复杂度
ArrayList查找的时间复杂度O(1),插入的时间复杂度O(n)
LinkedList查找的时间复杂度O(n),插入的时间复杂度为O(1)
4.26 HashMap在什么情况下会扩容?哪些操作会触发扩容
JDK1.7中HashMap扩容需要满足两个条件
1、存放新值的时候,当前以后元素的个数大于或者等于阈值
2、存放新值的时候,当前数组下已有值
JDK1.8扩容的条件
存放新值后,元素的个数大于阈值则进行扩容
哪些操作会触发扩容
1、put()
2、merge()
4.27 HashMap中put方法的执行过程
HashMap的put方法算是HashMap中比较核心的功能了, HashMap的数据结构为数组+链表,以key,value的形式存值,通过调用put与get方法来存值与取值。
它内部维护了一个Entry数组,得到key的hashCode值将其移位按位与运算,然后再通过跟数组的长度-1作逻辑与运算得到一个index值来确定数据存储在Entry数组当中的位置,通过链表来解决hash冲突问题。当发生碰撞了,对象将会储存在链表的下一个节点中。
4.28 HashMap检测到hash冲突后,将元素插入到链表的末尾还是开头
4.29 jdk1.8采用了红黑树,讲讲红黑树的特性,为什么人家一定要用红黑树而不是AVL
在CurrentHashMap中是加锁了的,实际上是读写锁,如果写冲突就会等待,
如果插入时间过长必然等待时间更长,而红黑树相对AVL树他的插入更快!
4.30 HashMap和HashTable底层实现有什么区别?HashTble和ConcurrentHashMap
HashTable
- 底层数组+链表实现,无论key还是value都不能为null,线程安全,实现线程安全的方式是在修改数据时锁住整个HashTable,效率低,ConcurrentHashMap做了相关优化
- 初始size为11,扩容:newsize = olesize*2+1
- 计算index的方法:index = (hash & 0x7FFFFFFF) % tab.length
HashMap
- 底层数组+链表实现,可以存储null键和null值,线程不安全
- 初始size为16,扩容:newsize = oldsize*2,size一定为2的n次幂
- 扩容针对整个Map,每次扩容时,原来数组中的元素依次重新计算存放位置,并重新插入
- 插入元素后才判断该不该扩容,有可能无效扩容(插入后如果扩容,如果没有再次插入,就会产生无效扩容)
- 当Map中元素总数超过Entry数组的75%,触发扩容操作,为了减少链表长度,元素分配更均匀
- 计算index方法:index = hash & (tab.length – 1)
ConcurrentHashMap
- 底层采用分段的数组+链表实现,线程安全
- 通过把整个Map分为N个Segment,可以提供相同的线程安全,但是效率提升N倍,默认提升16倍。(读操作不加锁,由于HashEntry的value变量是 volatile的,也能保证读取到最新的值。)
- Hashtable的synchronized是针对整张Hash表的,即每次锁住整张表让线程独占,ConcurrentHashMap允许多个修改操作并发进行,其关键在于使用了锁分离技术
- 有些方法需要跨段,比如size()和containsValue(),它们可能需要锁定整个表而而不仅仅是某个段,这需要按顺序锁定所有段,操作完毕后,又按顺序释放所有段的锁
- 扩容:段内扩容(段内元素超过该段对应Entry数组长度的75%触发扩容,不会对整个Map进行扩容),插入前检测需不需要扩容,有效避免无效扩容
4.31 快速失败和安全失败的区别是什么
Iterator的安全失败是基于对底层集合做拷贝,因此,它不受源集合上修改的影响。
java.util包下面的所有集合类都是快速失败的
java.util.concurrent包下面的所有类都是安全失败的
快速失败迭代器会抛出ConcurrentModificationException异常
安全失败迭代器永远不会抛出这样的异常