一、基础语法与面向对象
- 重载与重写的区别:重载是同一对象中方法名相同但参数列表不同的方法,编译时由编译器根据参数区分;重写是父子类(或接口与实现类)中方法名和参数列表都相同的方法,运行时由虚拟机根据对象实际类型确定调用哪个,可用
@Override检查是否重写。 - == 与 equals 的区别:对于基本类型,
==比较值;对于引用类型,==比较引用地址(是否为同一对象)。equals 的实现不同:Object 的 equals 本质是==,而 String、ArrayList 等的 equals 比较内容(如字符串的每个字符、集合的每个元素)。 - String、StringBuilder 和 StringBuffer 的区别:三者都可表示字符串,String 不可变(线程安全),后两者可变;StringBuilder 非线程安全,StringBuffer 线程安全(方法加同步锁)。大部分场景用 String;大量拼接时,多线程访问用 StringBuffer,单线程内用 StringBuilder 更高效。String 被 final 修饰是为了保证不可变,带来线程安全、可缓存等好处。
- Java 中的异常:Throwable 是顶层父类,分为 Error 和 Exception。Error 是无法恢复的错误(如内存溢出、栈溢出),捕获后通常无法恢复;Exception 是可恢复的异常,可通过 catch 处理或 throw 抛给上层。Exception 分检查异常(必须处理,如 try-catch 或 throws)和非检查异常(RuntimeException 及其子类,如空指针、数组越界,无需强制处理)。
二、集合类
- 常见数据结构:线性结构有动态数组(如 ArrayList,元素连续存储)、链表(如 LinkedList,元素通过节点链接)、栈(先进后出,LinkedList 的 push/pop/peek 可实现)、队列(先进先出,LinkedList 的 offer/poll 可实现);非线性结构有优先级队列(如 PriorityQueue,基于堆实现,适合排行榜)、哈希表(如 HashMap,key-value 存储,快速查找)、红黑树(如 TreeMap,自平衡二叉树)、跳表(如 ConcurrentSkipListMap,多级链表,性能接近红黑树)、B + 树(数据库索引常用)。
- Java 常见集合类:核心接口有 Collection(子接口 List、Set)和 Map。List 实现类中,ArrayList 基于数组,随机访问快、增删(非尾部)影响其他元素;LinkedList 基于链表,随机访问慢、增删(非定位阶段)快;Vector 基于数组,线程安全。Set 实现类中,HashSet 基于 HashMap,元素唯一(需实现 hashCode 和 equals)。Map 实现类中,HashMap 底层是数组 + 链表 + 红黑树,key 唯一;LinkedHashMap 在 HashMap 基础上用链表记录插入顺序(可做 LRU 缓存);TreeMap 基于红黑树;Hashtable 线程安全(方法加 synchronized);ConcurrentHashMap 线程安全(锁链表,并发度高,get 无锁靠 volatile 保证可见性)。
- HashMap 原理(数据结构):底层是数组 + 链表 + 红黑树。数组通过 key 的 hashCode 计算索引,实现 O (1) 存取;因数组容量有限,会发生哈希冲突,用链表存储冲突元素(此时存取复杂度 O (n));当链表长度≥8 且数组容量≥64 时,链表转为红黑树(复杂度 O (log n)),节点减少到一定程度会退化为链表。
- HashMap 原理(扩容):扩容因子 0.75,初始容量 16,当元素数超过容量 ×0.75 时扩容(容量翻倍)。扩容后重新计算 key 的索引,部分 key 会移动到新位置(通过 (n-1)&hash 计算,n 为新容量)。
三、网络编程
BIO、NIO、AIO 的区别:三者核心差异在处理客户端连接、数据等待、数据复制阶段的线程状态。BIO 中线程在这三个阶段都阻塞,高并发下线程资源紧张;NIO 在连接和数据等待阶段非阻塞,结合多路复用技术(事件驱动),用少量线程处理大量请求,线程利用率高;AIO 在数据复制阶段也解放线程,通过回调处理,适合高并发场景。
四、IO 流
IO 流按单位分字节流(父类 InputStream、OutputStream)和字符流(父类 Reader、Writer)。转换流(InputStreamReader、OutputStreamWriter)用于字节流转字符流;缓冲流(如 BufferedInputStream)通过缓冲提高效率;对象流(ObjectInputStream、ObjectOutputStream)配合序列化实现对象与字节流的转换。
五、线程与并发
- ThreadLocal 原理:用于多线程变量隔离,每个线程有 ThreadLocalMap,以 ThreadLocal 为 key 存储隔离资源。set 方法将资源存入当前线程的 map,get 方法从中获取,用完需调用 remove () 避免内存泄漏。
- 悲观锁与乐观锁:悲观锁(如 synchronized、Lock)认为会有竞争,失败线程阻塞,适合竞争多、独占时间长的场景;乐观锁(如 AtomicInteger)认为竞争少,失败线程重试,适合竞争少、快速处理的场景。
- synchronized 原理:重量级锁中,线程通过 Monitor 对象的 owner 属性竞争,成功则加锁,失败则自旋重试或进入等待队列。锁升级过程:单线程加锁用偏向锁,交替加锁用轻量级锁,竞争时升级为重量级锁(Java 15 后偏向锁废弃)。
- synchronized 和 volatile 对比:volatile 保证共享变量的可见性和有序性,但不保证原子性;synchronized 保证原子性、可见性和有序性。
- 线程池核心参数:核心线程数(常驻线程)、最大线程数(核心线程 + 救急线程)、存活时间(救急线程空闲时长)、时间单位、工作队列(存放待处理任务)、线程工厂(创建线程)、拒绝策略(队列满且线程全忙时,如 AbortPolicy 抛异常、CallerRunsPolicy 让提交线程处理等)。
六、JVM 虚拟机
- 堆内存结构:传统垃圾回收器将堆分为老年代和年轻代(Eden、S0、S1);G1 回收器将堆分为多个 Region,可分别作为 Eden、幸存区、老年代、巨型对象区。
- 垃圾回收算法:标记 - 清除算法(快但产生碎片);标记 - 整理算法(无碎片但慢);标记 - 复制算法(将内存分为 S0 和 S1,复制存活对象到 S1 后清空 S0,无碎片,适合存活对象少的场景)。
- 伊甸园、幸存区、老年代细节:对象初始在 Eden,年轻代回收(标记 - 复制)后存活对象进入 S0;再次回收时,Eden 和 S0 的存活对象复制到 S1,二者互换;多次回收后存活的对象晋升老年代。大对象在不同回收器中处理不同,如 CMS 中超过阈值直接进老年代,G1 中巨型对象存于专用 Region。
七、Lambda 表达式
Lambda 表达式是匿名函数(语法:(参数) -> 表达式),本质是函数对象,用于行为参数化场景(如 Stream API、MyBatisPlus 的 QueryWrapper)。与匿名内部类相比,Lambda 需配合函数式接口,语法更简洁,this 含义不同,运行时动态生成类。
八、反射及泛型
- 反射:Java 提供的 API,可在运行时加载类、获取类信息(属性、方法等)、创建对象、调用方法。广泛用于框架(如 Spring 的 Bean 创建、MyBatis 的结果映射),但效率较低。
- 泛型:实现类型参数化,可用于类、接口、方法,提供编译时类型检查(避免运行时转换错误),提高代码通用性(如 List<T>可存储任意类型元素)。
九、Tomcat 优化
Tomcat 优化可调整线程池和网络配置,如 springboot 默认配置中,max-connections 控制最大连接数,accept-count 控制连接队列数,threads.max 控制最大线程数,threads.min-spare 控制最小备用线程数。JDK 21 配合 SpringBoot 3.2.x 可使用虚拟线程优化,提升并发处理能力。