Java 面试笔记
1 HashMap 与 Hashtable 的区别
- 线程安全:HashMap 不是线程安全的,不能在没有同步代码的情况下被多线程共享;Hashtable 是线程安全的,可以被多线程共享;
- null 值:HashMap 允许一个 null key 和多个 null value;Hashtable 不允许任何 null key 或 value;
- 选择:如果不需要线程同步,通常首选 HashMap 而不是 Hashtable。
为什么 Hashtable 不允许 null 而 HashMap 允许
要从 Hashtable 中成功存取对象,key 必须实现 hashCode 方法和 equals 方法。由于 null 不是对象,无法实现这些方法。HashMap 是 Hashtable 的改进版本,创建得更晚,所以放宽了这个限制。
2 JVM 面试要点
JVM 内存结构
- 线程私有:虚拟机栈(栈帧:局部变量表、操作数栈、方法返回地址)、本地方法栈、程序计数器;
- 线程共享:堆(对象实例)、方法区(类信息/常量/静态变量,JDK8 后为元空间 Metaspace,使用本地内存);
- 类加载信息存储在方法区/元空间。
类加载过程
加载(Loading)→ 验证(Verification)→ 准备(Preparation)→ 解析(Resolution)→ 初始化(Initialization)。
- 类加载器:启动类加载器(Bootstrap)、扩展类加载器(Extension)、应用类加载器(Application),双亲委派模型;
- 磁盘文件到 JVM 的加载过程即以上五步,加载阶段把字节流读入内存形成 Class 对象。
垃圾回收
- 判断回收:可达性分析,GC Roots:虚拟机栈中引用的对象、方法区中静态属性引用的对象、方法区中常量引用的对象、本地方法栈中 JNI 引用的对象等;
- minor gc / full gc:新生代 Minor GC(Eden 满触发),老年代 Full GC;
- 四种引用:
- 强引用:引用存在则永不回收,内存不足抛 OOM;
- 软引用 SoftReference:内存不足先回收,适合缓存;
- 弱引用 WeakReference:下次 GC 即回收;
- 虚引用 PhantomReference:虚引用随时可能被回收,主要用于堆外内存回收跟踪。
四种引用作为 GC Root 的判断
见上面 GC Roots 列表。
3 线程池
- 原理:核心线程 corePoolSize → 工作队列 workQueue → 最大线程数 maximumPoolSize → 拒绝策略 handler;
- 有界 vs 无界队列:无界队列(如 LinkedBlockingQueue 不设容量)任务会一直排队,不会创建非核心线程,可能导致任务积压、内存溢出;有界队列(如 ArrayBlockingQueue)队列满后才创建非核心线程,超过最大线程数执行拒绝策略,能控制资源占用;
- 应用场景:CPU 密集型任务核心线程数 = CPU 核数+1;IO 密集型 = CPU 核数*2。
4 集合类中为什么不用 int 基本类型
Java 集合只能存放对象的引用,不能存放基本数据类型。因为泛型擦除后所有元素都以 Object 处理,基本类型需要通过自动装箱(Integer 等包装类)存入。用包装类而不是 int 的另一个原因是 int 没有 hashCode/equals 方法。
5 ReentrantLock 与 synchronized
| 维度 | synchronized | ReentrantLock |
|---|---|---|
| 实现 | JVM 关键字(monitorenter/exit) | JDK 类(AQS) |
| 锁获取 | 隐式 | 显式 lock/unlock |
| 中断 | 不响应中断 | lockInterruptibly 支持中断 |
| 公平性 | 非公平 | 可配置公平/非公平 |
| 条件 | wait/notify | Condition 接口 |
| 可重入 | 支持 | 支持 |
6 Java 面试考点汇总
- 重载/重写和多态;
- 同步和异步;
- 手写生产者消费者模式(wait/notify 或 BlockingQueue);
- BlockingQueue 如何实现阻塞(Condition 的 await/signal);
- JVM 判断回收、GC Roots、minor gc/full gc;
- 类加载过程及不足;
- Java 四种引用;
- 方法区。
阅读 —
·
全站 —