1. java集合:
    java集合分为Collection和Map两种。
    Collection主要分为List和Set。
    List是有序的,值可以重复。
    Set无序,值不可重复。如果一个对象要存储在Set中,需要重写equals和hashcode方法。

  2. 如果你是面的JAVA,
    首先当然是JAVA的基础知识:数据结构(Map,List,Set等),设计模式,算法,线程相关,IO/NIO,序列化等等
    其次是高级特征:反射机制,并发与锁,JVM(GC策略,类加载机制,内存模型)等等。

  3. List常用的有ArrayList和LinkedList。ArrayList底层使用数组,查询快(内存中分配连续空间,可以按索引查找),插入、修改和删除慢。
    LinkedList底层使用链表,在一个元素中存放上一个或下一个元素内存中的首地址。查询慢,插入、修改和删除快。
    ArrayList使用在查询较多,修改较少的场景。LinkedList使用在查询较少,修改较多的场景。

  4. 为什么用HashMap?
    HashMap是一个散列桶(数组和链表),它存储的内容是键值对(key-value)映射
    HashMap采用了数组和链表的数据结构,能在查询和修改方便继承了数组的线性查找和链表的寻址修改
    HashMap是非synchronized,所以HashMap很快(效率较高)
    HashMap可以接受null键和值,而Hashtable则不能(原因就是equals()方法需要对象,因为HashMap是后出的API经过处理才可以)
    HashTable是线程安全的。
    ConcurrentHashMap是线程安全的,效率较高。它将map默认分为16段Segment(分别加锁)。

  5. HashMap的工作原理是什么?
    HashMap是基于hashing的原理,我们使用put(key, value)存储对象到HashMap中,使用get(key)从HashMap中获取对象。当我们给put()方法传递键和值时,我们先对键调用hashCode()方法,计算并返回的hashCode是用于找到Map数组的bucket位置来储存Node 对象。这里关键点在于指出,HashMap是在bucket中储存键对象和值对象,作为Map.Node 。
    以下是HashMap初始化 ,简单模拟数据结构
    java面试汇总(一)

Node[] table=new Node[16]  散列桶初始化,table
class Node {
 hash;//hash值
      key;//键
 value;//值
 node next;//用于指向链表的下一层(产生冲突,用拉链法)
}

以下是具体的put过程(JDK1.8版)
1、对Key求Hash值,然后再计算下标
2、如果没有碰撞,直接放入桶中(碰撞的意思是计算得到的Hash值相同,需要放到同一个bucket中)
3、如果碰撞了,以链表的方式链接到后面
4、如果链表长度超过阀值( TREEIFY THRESHOLD==8),就把链表转成红黑树,链表长度低于6,就把红黑树转回链表
5、如果节点已经存在就替换旧值
6、如果桶满了(容量16*加载因子0.75),就需要 resize(扩容2倍后重排)

以下是具体get过程(考虑特殊情况如果两个键的hashcode相同,你如何获取值对象?)
当我们调用get()方法,HashMap会使用键对象的hashcode找到bucket位置,找到bucket位置之后,会调用keys.equals()方法去找到链表中正确的节点,最终找到要找的值对象。
java面试汇总(一)

  1. 有什么方法可以减少碰撞?
    尽量少的调用equals方法。
    扰动函数可以减少碰撞,原理是如果两个不相等的对象返回不同的hashcode的话,那么碰撞的几率就会小些,这就意味着存链表结构减小,这样取值的话就不会频繁调用equals方法,这样就能提高HashMap的性能。(扰动即Hash方法内部的算法实现,目的是让不同对象返回不同hashcode。)
    使用不可变的、声明作final的对象,并且采用合适的equals()和hashCode()方法的话,将会减少碰撞的发生。不可变性使得能够缓存不同键的hashcode,这将提高整个获取对象的速度,使用String,Interger这样的wrapper类作为键是非常好的选择。为什么String, Interger这样的wrapper类适合作为键?因为String是final的,而且已经重写了equals()和hashCode()方法了。不可变性是必要的,因为为了要计算hashCode(),就要防止键值改变,如果键值在放入时和获取时返回不同的hashcode的话,那么就不能从HashMap中找到你想要的对象。

  2. HashMap中hash函数怎么是是实现的?
    我们可以看到在hashmap中要找到某个元素,需要根据key的hash值来求得对应数组中的位置。如何计算这个位置就是hash算法。前面说过hashmap的数据结构是数组和链表的结合,所以我们当然希望这个hashmap里面的元素位置尽量的分布均匀些,尽量使得每个位置上的元素数量只有一个,那么当我们用hash算法求得这个位置的时候,马上就可以知道对应位置的元素就是我们要的,而不用再去遍历链表。 所以我们首先想到的就是把hashcode对数组长度取模运算,这样一来,元素的分布相对来说是比较均匀的。但是,“模”运算的消耗还是比较大的,能不能找一种更快速,消耗更小的方式,我们来看看JDK1.8的源码是怎么做的(被楼主修饰了一下)

   static final int hash(Object key) {
        if (key == null){
            return 0;
        }
         int h;
         h=key.hashCode();返回散列值也就是hashcode
          // ^ :按位异或
          // >>>:无符号右移,忽略符号位,空位都以0补齐
          //其中n是数组的长度,即Map的数组部分初始化长度
         return  (n-1)&(h ^ (h >>> 16));
    }

java面试汇总(一)
简单来说就是

1、高16bt不变,低16bit和高16bit做了一个异或(得到的HASHCODE转化为32位的二进制,前16位和后16位低16bit和高16bit做了一个异或)
2、(n·1)&hash=->得到下标

相关文章:

  • 2021-05-17
  • 2021-10-16
  • 2021-09-03
  • 2021-10-12
  • 2022-02-08
  • 2022-02-17
猜你喜欢
  • 2021-06-15
  • 2021-12-13
  • 2021-08-31
  • 2021-07-16
  • 2021-11-17
  • 2021-11-17
相关资源
相似解决方案