1、hashCode相等的两个对象一定相等吗?equals呢?相反呢?
闭卷:
hashCode与对象在物理内存上的地址相关,是其物理地址经过特定计算后得到的标识码,可能会出现冲突,所以hashCode相等两个对象不一定相等。
两个对象equals相等时,首先必须hashCode相等,然后必须值相等,所以equals相等时,两个对象一定是相等的。
反过来,相等的两个对象,hashCode和equals都是相等的。
开卷:
hashCode()主要运用在Hash表数据结构(如HashMap)中,按照Object中的规约,在重写equals()时,最好重写hashCode()。
equals()相等时,hashCode()一定相等,但由于Hash冲突,可能惠出现equals()不等但hashCode()仍然相等的情况。
整理:
equals()和hashCode()是两个独立的方法,本身之间并没有什么对等关系。
但为了在Hash表数据结构中正确使用,Object类的作者在hashCode()方法的注释中与开发者协定了如下规约:
当两个对象equals()相等,hashCode()也一定返回相同的整数。
hashCode()的默认实现,是将对象的内部地址转化为整数。
2、介绍一下集合框架。
闭卷:
Java中集合类都是从继承Collection接口开始的。平时用的比较多的有List、Map。List其下主要有ArrayList、LinkedList这两种实现,Map的主要实现有HashMap。
ArrayList其底部的数据结构实现其实就相当于数组,数组的初始容量为10,当数组容量满时,将其容量扩大0.5倍。
LinkedList其数据结构实现相当于链表,每次新增值时新增一个节点。
HashMap的初始容量为16,当容量快满时,将其容量扩大到2倍。其数据结构相当于Hash列表,用拉链法来解决Hash冲突问题。
开卷:
在集合框架的类继承体系中,最顶层有两个接口:
Collection表示一组纯数据
Map表示一组key-value对
整理: HashMap
HashMap本质上是一个哈希表,对于哈希表来说,解决哈希冲突的方式(开放地址法[线性探测、二次探测、伪随机探测]、再哈希法、链地址法)决定了它本身的一些特性。HashMap通过链地址法来解决哈希冲突,因此,它的数据结构由一个数组和多组链表构成。
在具体确定数据在桶上分布位置的时候,最终计算出来的hash值要对桶的容量取模。HashMap通过将key对象hash值的高16位与低16位做异或运算作为新的散列哈希(扰动函数),通过这种方式重新计算的hash值,可以使得数据的分布不单单只受hash低位的影响,还综合考虑了高位,提高了分散程度。
HashMap在初始化的时候,总是会使得最终的容量为2的幂。之所以这么设计,与取模方式有关。对于n、x,n为2的幂,x为任意整数,那么有\( x & (n - 1) = x % n \)
。这种取模运算的计算速度更加快,也更优雅。
涉及HashMap主要的操作包括三个:put()、get()、resize()。put()用来写入值、get()用来获取值、resize()用来初始化桶以及扩容。
resize()是HashMap中最核心的方法,实际扩容的时候,扩容包含两方面的内容:一是扩容桶的大小,二是增大扩容阈值。桶的扩容:当实际数据节点数大于扩容阈值时,开始发生扩容,新的桶容量为旧容量的2倍。阈值的增长:初始化,以及桶的容量小于16的情况下,阈值=桶容量*加载因子;当容量大于等于16,新阈值=旧阈值*2。
3、HashMap、HashTable底层实现有什么区别?
闭卷:
HashMap是线程不安全的,它的增、删、改、查是开放的。而HashTable的在进行修改时,实现了粗粒度的内部锁,所以是线程安全的。
开卷:
整理:
4、HashMap和TreeMap什么区别?底层数据结构是什么?
闭卷:
HashMap是无序的,通过Hash列表来实现数据的Key-Value索引。而TreeMap是有序的,其底层数据结构是红黑树。
开卷:
整理:
5、线程池都有什么参数?底层如何实现?
闭卷:
CoreSize、MaxSize、时间单位
开卷:
整理:
6、synchronized和Lock有什么区别?
闭卷:
synchronized称为内部锁,Lock称为显示锁。
在使用方法上,synchronized是通过抢夺引导锁,互斥执行锁所限定的方法或者代码块,内部锁是不可重入的。
Lock必须成对的使用lock()与release()来加锁与释放锁,可以实现不可重入锁,也可以实现可重入锁。
开卷:
整理:
7、ThreadLocal是什么?底层如何实现?写一个例子。
闭卷:
ThreadLocal是线程的本地变量,当声明一个ThreadLocal对象时,每个线程都将有这个对象的副本。
其主要实现原理为:内部维护一个ThreadLocalMap(其本质就是一个Map),以当前线程为Map的Key值。这样,每次取变量值的时候,都是通过传入当前线程对象来获取变量值。
开卷:
Thread内部存在一个ThreadLoaclMap对象,用来存储一些贯穿线程整个生命周期的参数。ThreadLoaclMap的数据结构就是一个哈希表,它采用线性探测法来解决哈希冲突。为了保证线程数据安全,这个ThreadLoaclMap对象是不可以被直接访问的,而是通过ThreadLocal来间接访问。
整理:
8、说明下volitile的工作原理。
闭卷:
volitle是通过设置内存屏障,保证变量的可见性。volatile变量规则:对一个volatile变量的写操作先行发生于后面(时间上)对这个变量的读操作。
开卷:
整理:
9、简述下CAS,说说它是如何实现的。
闭卷:
Compare And Swap。用一组原子操作,实现对变量的互斥访问。包括两个步骤,一、比较,比较值是否改变;二、替换,如果值已改变就进行替换,未改变就不进行替换。
开卷:
CAS是一种乐观锁的实现。CAS是一种系统原语,原语属于操作系统用语范畴,是由若干条指令组成的,用于完成某个功能的一个过程,并且原语的执行必须是连续的,在执行过程中不允许被中断,也就是说CAS是一条CPU的原子指令,不会造成所谓的数据不一致问题。在JAVA中,主要有compareAndSwapObject、compareAndSwapInt、compareAndSwapLong这个三个CAS方法。并发包中的原子操作类(Atomic系列),从JDK 1.5开始提供了java.util.concurrent.atomic包,在该包中提供了许多基于CAS实现的原子操作类,用法方便,性能高效。
ABA问题:当第一个线程执行CAS操作,在获取到当前变量V,准备修改为新值U前,另外两个线程已连续修改了两次变量V的值,最终使得该值又恢复为旧值,这样的话,我们就无法正确判断这个变量是否已被修改过。在Java中解决ABA问题,我们可以使用AtomicStampedReference、AtomicMarkableReferenc。
整理:
10、请用4种方法写一个单例模式。
整理:
见单例模式