java面试题

1.list和set的区别?

list底层是数组,有序可重复,按对象进入顺序保存元素,可以有多个null元素,可以使用该iterator迭代器取出元素,也可以直接get(int index)下标,取出元素。底层数据结构:动态数组(arraylist)或链表(Linkedlist)

set底层是,无序不可重复,最多只能储存一个null元素,只能使用iterator接口取出所有元素,再逐一遍历各个元素。底层数据结构:hash表(hashset) 或红黑树(treeset)

2.hashcode和equals

hashcode()的作用是获取hash码,也称为散列码,哈希码的作用是确定该对象在hash表的索引位置,java中任何类都包含了hashcode()函数,散列表存储的是键值对,他的特点是:能根据键快速的找到值,这就利用了哈希码。

以hashset为例,来说明为什么要用hash码,当hashset存储数据时,首先会计算该对象的hashcode值,判断该位置是否有对象,如果没有。hashset对假设该对象没有重复出现,如果有值,那么会调用equals方法判断该对象是否相同,如果相同,hashset会拒绝该对象入集合,如果不同,hashset会重新散列到其他位置,降低了equals的频率。

重写了equals方法,就必须要重写hashcode方法:下面是string中重写的hashcode方法。

 public int hashCode() {
        int h = hash;
        if (h == 0 && value.length > 0) {
            char val[] = value;

            for (int i = 0; i < value.length; i++) {
                h = 31 * h + val[i];
            }
            hash = h;
        }
        return h;
    }

3.ArrayList和LinkedList的区别?

ArrayList底层是动态数组,连续内存存储。可自动扩容,默认容量是10,当数据超过数组下标时自动扩容,每次扩容那个1.5倍,其尾部插入元素并指定初始容量效率较高,中间插入元素效率较低(因为在中间插入的话。他要把后面的所有元素向后复制移动)读取效率较高,可以直接根据数组下标获取元素。

LinkedList底层时链表,可分散在内存中存储。其尾部插入元素效率不及ArrayList,但是中间插入元素效率较高,(只需要断开要插入位置的链表,然后用上一个元素的next指针,指向要插入的元素,然后该元素的pre节点存储上一个元素的数据,然后该元素的next节点,储存她上一个元素next节点原来存储的值。)读取效率较低,因为他要一个元素一个元素的遍历。遍历LinkedList必须使用iterator迭代器,不能使用for循环。因为每次for循环,get(i)获取元素时,都会从头吧链表再遍历一次。

4.hashmap及hashtable的区别和底层实现?

区别:

1.HashMap没有使用synchronized修饰,非线程安全,Hashtable是线程安全的。

2.HashMap允许key和value值为null,Hashtable不允许。

底层实现:

数组+链表

jdk8后链表长度达到8、数组长度达到64,链表就会转为红黑树存储,元素以内部node节点存在。

1.当数据进入hashset,会先计算key的hash值,二次hash对数组取模,然后找到对应的数组下标。

2.如果没有产生hash冲突,则直接创建node存入数组。

3.如果存在hash冲突,则先进行equals比较,如果相同,则替换掉该位置的元素,如果不同,那么就判断链表高度插入链表,当链表高度大于8,数组长度大于64,则转换为红黑树。

4.key为null,存在下标为0的位置。

5.ConcurrentHashMap原理

jdk8中:

数据结构:synchronized+CAS+node+红黑树,node的next和val都用volatile修饰,保证线程可见性。

查找、赋值、替换操作都用cas,

锁:锁链表的head节点,不影响其他节点,锁粒度更细,效率更高,扩容时,阻塞所有读写操作,并发扩容。

读写操作无锁:

node的next和val都是用volatile修饰,读写线程对该变量互相可见。

数组用volatile修饰,保证扩容时被读线程感知。

你可能感兴趣的:(java面试,java,开发语言)