Java笔试面试高频问题复习记录

本文详细梳理了Java面试中常见的笔试题,涵盖了Java容器、多线程、关键字、JVM内存、操作系统、计算机网络等多个方面。重点讲解了HashMap与Hashtable的区别、ArrayList的扩容机制、线程安全问题、synchronized与Lock的对比,以及并发容器和多线程同步原理解析。此外,还涉及了Java内存区域、数据库事务特性、MySQL索引和数据库设计范式等内容,是Java开发者面试准备的重要参考资料。
摘要由CSDN通过智能技术生成

简答题

提示:使用CSDN右侧(网页版)的“目录”功能阅读体验更佳

Java容器

Java集合类继承关系

Java集合类继承关系,来自Cyc大佬的GitHub仓库,地址附在文末,强烈推荐!

详解1

详解2

1.请你说明HashMap和Hashtable的区别?

HashMap和Hashtable都实现了Map接口,因此有很多相似点,但是也有以下不同点:

  • HashMap允许键和值为空值(但只能有一个键为空值),Hashtable不允许空值作为键或值
  • HashMap是线程不安全的,而HashTable的方法基本都使用synchronized修饰了,因此在多线程环境下Hashtable是线程安全的。
  • 因为Hashtable是同步的,所以在效率上要低于HashMap,因此被认为是一个一般不使用的遗留类(如果需要保证线程安全一般使用JUC的ConcurrentHashMap类)
  • 在未给定容量时,HashMap的默认初始容量是16,之后每次扩容会变为原来的2倍;Hashtable默认大小是11,之后每次扩容会变为原来的2n+1;在指定初始容量时,Hashtable 会直接使用你给定的大小,而 HashMap 会将其扩充为2的幂次方大小(HashMap 中的tableSizeFor()方法保证)。也就是说 HashMap 总是使用2的幂作为哈希表的大小。
  • JDK1.8后的HashMap在解决哈希冲突时有了变化,当链表长度大于阈值(默认8)时,会将链表转化为红黑树,以减少搜索时间,而Hashtable没有这样的机制。

2.请你说明HashMap 和 HashSet区别?

  • HashMap实现了Map接口,而HashSet实现的是Set接口
  • HashMap以键值对的形式存储对象,HashSet仅存储对象
  • HashMap使用键(key)计算Hashcode,HashSet使用成员对象来计算hashcode值,对于两个对象来说hashcode可能相同,所以equals()方法用来判断对象的相等性

3.ArrayList

ArrayList底层使用动态数组存储数据,初始容量为10,且支持快速随机访问(实现RandomAccess)

虽然ArrayList的初始容量是10,但在以无参构造方法创建ArrayList的时候新建的是一个空数组,只有等到添加元素时才会分配容量。即在添加第一个元素后容量分配为10。

ArrayList的扩容底层是由复制数组实现的,操作代价较高,最好在创建时指定足够的容量。

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
private static final int DEFAULT_CAPACITY = 10;
ArrayList的自动扩容

ArrayList的扩容发生在添加元素时,依次涉及到5个方法。

1.add()方法
添加元素前将当前元素数+1作为参数调用ensureCapacityInternal()方法。

public boolean add(E e) {
   
    ensureCapacityInternal(size + 1);
    elementData[size++] = e;
    return true;
}

2.ensureCapacityInternal()方法

得到最小扩容量

当添加第一个元素时,可知参数minCapacity传入时为1,在if语句执行后为10。

private void ensureCapacityInternal(int minCapacity) {
   
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
   
        // 获取默认的容量和传入参数的较大值
        minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
    }
    ensureExplicitCapacity(minCapacity);
}

3.ensureExplicitCapacity()方法

判断是否需要扩容

private void ensureExplicitCapacity(int minCapacity) {
   
    modCount++;
    // overflow-conscious code
    if (minCapacity - elementData.length > 0)
        //调用grow方法进行扩容,调用此方法代表已经开始扩容了
        grow(minCapacity);
}

4.grow()方法

ArrayList扩容的核心方法,在确定了新容量后通过Arrays.copyOf()方法将原数组复制到新数组里

private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

private void grow(int minCapacity) {
   
    //旧的容量
    int oldCapacity = elementData.length;
    //扩容为旧容量的1.5倍(JDK1.8),在JDK1.6以前为旧容量的1.5倍+1;
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    //如果扩容后还是小于最小所需容量,则将新容量设为最小所需容量
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值