Java封神之路:Java面试备战(八)

4.16 以下结构中,插入性能最高的是

4.17 以下结构中,哪个最适合当作stack使用

在这里插入图片描述

4.18 Map的实现类中,哪些是有序的,哪些是无序的,有序的是如何保证其有序性,你觉得哪个有序性性能更高,你有没有更好或者更高效的实现方式

  1. Map的实现类有HashMap,LinkedHashMap,TreeMap

  2. HashMap是有无序的,LinkedHashMap和TreeMap都是有序的(LinkedHashMap记录了添加数据的顺序;TreeMap默认是自然升序)

  3. LinkedHashMap底层存储结构是哈希表+链表,链表记录了添加数据的顺序

  4. TreeMap底层存储结构是二叉树,二叉树的中序遍历保证了数据的有序性

  5. 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异常

安全失败迭代器永远不会抛出这样的异常

猜你喜欢

转载自blog.csdn.net/weixin_54707168/article/details/113975161