跳到主要内容Java 面试核心考点解析:基础、JVM 与并发编程实战 | 极客日志Javajava算法
Java 面试核心考点解析:基础、JVM 与并发编程实战
本文涵盖 Java 面试的核心领域,包括基础语法、JVM 内存模型、垃圾回收机制、多线程并发编程以及 Spring 生态系统的 IOC、AOP 和 Bean 生命周期。内容梳理了 HashMap 与 Hashtable 区别、volatile 关键字原理、线程池构建策略、MyBatis 分页机制及 Spring Boot 自动配置逻辑。旨在帮助开发者系统复习关键技术点,应对实际面试场景中的深度提问。
CodeArtist0 浏览 一、基础篇
1.1 Java 语言有哪些特点
- 简单易学,拥有丰富的类库。
- 面向对象(Java 最重要的特性,降低程序耦合度,提高内聚性)。
- 与平台无关性(JVM 是 Java 跨平台使用的根本)。
- 可靠安全。
- 支持多线程。
1.2 面向对象和面向过程的区别
面向过程:分析解决问题的步骤,用函数实现。性能较高,常用于单片机、嵌入式开发。以函数为单位,逐步完成,后期维护可能牵一发而动全身。
面向对象:以对象为最小单位,将事务分解成各个对象。目的是描述事物在解决问题过程中的行为。具有封装、继承、多态特性,易维护、易复用、易扩展,能设计出低耦合系统。但性能略低于面向过程。
1.3 八种基本数据类型的大小及封装类
| 基本类型 | 大小(字节) | 默认值 | 封装类 |
|---|
| byte | 1 | (byte)0 | Byte |
| short | 2 | (short)0 | Short |
| int | 4 | 0 | Integer |
| long | 8 | 0L | Long |
| float | 4 | 0.0f | Float |
| double | 8 | 0.0d | Double |
| boolean | - | false | Boolean |
| char | 2 | \u0000 | Character |
注:
int 是基本类型,Integer 是引用类型。int 默认值为 0,Integer 为 null。这有助于区分 0 和 null。使用引用前必须实例化,否则会报错。
- 基本类型声明时自动分配空间;引用类型仅分配引用空间,需实例化开辟数据空间。数组赋值复制的是引用,修改一个会影响另一个。
- JVM 中无 boolean 专用字节码指令,表达式操作使用 int 代替,boolean 数组编码为 byte 数组。单用占 4 字节,数组中占 1 字节。这是为了适配 32 位 CPU 的高效存取。
1.4 标识符的命名规则
含义:程序中自定义的内容,如类名、方法名、变量名等。
硬性要求:
- 包含英文字母、0-9、$、_。
- 不能以数字开头。
- 不是关键字。
规范建议:
- 类名:首字符大写,后续单词首字母大写(大驼峰式)。
- 变量/方法名:首字母小写,后续单词首字母大写(小驼峰式)。
1.5 instanceof 关键字的作用
用于测试对象是否属于某个类的实例。
boolean result = obj instanceof Class;
obj 为对象,Class 为类或接口。
- 若
obj 是该类或其子类、接口的实现类,返回 true。
- 注意:编译器会检查转换可行性。基本类型不能使用 instanceof。
- 若
obj 为 null,返回 false。
1.6 Java 自动装箱与拆箱
- 装箱:基本类型转包装器类型(如 int -> Integer),调用
Integer.valueOf(int)。
- 拆箱:包装器类型转基本类型(如 Integer -> int),调用
Integer.intValue()。
public class Main {
public static void main(String[] args) {
Integer i1 = 100; Integer i2 = 100;
Integer i3 = 200; Integer i4 = 200;
System.out.println(i1 == i2);
System.out.println(i3 == i4);
}
}
原因:Integer.valueOf 内部使用了缓存池(-128 到 127)。在此范围内的数值直接返回缓存对象引用,超出范围则创建新对象。
1.7 重载和重写的区别
- 发生在父类与子类之间。
- 方法名、参数列表、返回类型(子类可为父类返回类型的子类)必须相同。
- 访问权限不能小于父类方法。
- 不能抛出比父类更宽泛的检查异常。
- 同一类中,同名方法但参数列表不同(类型、个数、顺序)。
- 返回值类型不影响重载判断。
1.8 equals 与 == 的区别
- ==:比较内存地址。对于基本类型比较值,对于对象比较引用地址。
- equals:比较内容。Object 类中的 equals 默认等同于 ==,通常需重写(如 String)。
- 建议:阿里代码规范推荐使用 equals 比较对象,且常量在前(避免空指针)。
1.9 Hashcode 的作用
用于集合查找效率优化。通过哈希算法将对象映射到存储区域。若位置已有元素,则调用 equals 比较。hashCode 方法本质是根据内存地址换算出的值,帮助快速定位物理位置。
1.10 String、StringBuffer 和 StringBuilder 的区别
- String:不可变字符数组。每次修改生成新对象。
- StringBuffer:可变字符数组,线程安全(加锁),性能稍低。
- StringBuilder:可变字符数组,非线程安全,性能高。
- 建议:频繁字符串操作使用 StringBuffer 或 StringBuilder。
1.11 ArrayList 和 LinkedList 的区别
- ArrayList:基于数组,查询快 O(1),增删慢(需移动数据)。可自动扩容。
- LinkedList:双向链表,增删快,查询慢 O(n)。适合频繁插入删除场景。
1.12 HashMap 和 Hashtable 的区别
- 父类:HashMap 继承 AbstractMap,Hashtable 继承 Dictionary。
- null 支持:HashMap 允许 key 为 null(唯一),value 可为 null;Hashtable 不允许。
- 线程安全:HashMap 不安全;Hashtable 每个方法 synchronized,线程安全但效率低。
- 扩容:HashMap 初始 16,扩容 2 倍;Hashtable 初始 11,扩容 2 倍 +1。
- hash 计算:HashMap 异或移位,Hashtable 直接 hashcode。
- 替代方案:多线程建议使用 ConcurrentHashMap。
1.13 Collection 包结构与 Collections 的区别
- Collection:集合根接口,子接口有 Set、List 等。
- Collections:工具类,提供静态方法(搜索、排序、同步化),不可实例化。
1.14 Java 的四种引用
- 强引用:最常见,OOM 时不回收。
String str = new String("str")。
- 软引用:内存不足时回收。适用于缓存场景。
- 弱引用:GC 发现即回收。WeakHashMap 的 Key 常用此方式。
- 虚引用:回收前放入 ReferenceQueue。用于资源释放前的处理。
1.15 泛型常用特点
Java SE 1.5 引入。允许编写被不同类型对象重用的代码。约束集合类型,避免运行时类型转换错误。
1.16 Java 创建对象的方式
- new 关键字。
- 反射机制 (
Class.newInstance)。
- Clone 机制。
- 序列化机制。
1.17 两个不相等的对象能有相同的 hashCode 吗
有可能,即 Hash 冲突。处理方式包括拉链法、开放定址法、再哈希法。
1.18 深拷贝和浅拷贝的区别
- 浅拷贝:复制对象本身,引用仍指向原对象。
- 深拷贝:复制对象及其引用的所有对象,完全独立。
1.19 final 的用法
- 类不可继承。
- 方法不可重写。
- 变量不可变(引用不变,内容可变;或基本类型值不变)。
- JVM 尝试内联优化。
- 编译期常量存入常量池。
1.20 static 的用法
- 静态变量/方法(类共享)。
- 静态块(初始化)。
- 静态内部类。
- 静态导包(import static)。
1.21 3*0.1==0.3 返回值
1.22 a=a+b 与 a+=b 的区别
+= 会进行隐式类型转换,a=a+b 不会。例如 byte 运算结果提升为 int,直接赋值报错,需用 +=。
1.23 try catch finally 执行顺序
finally 总会执行(除非 JVM 退出)。finally 在 return 表达式运算后执行,但不改变已保存的返回值。finally 中不建议 return。
1.24 Exception 与 Error 包结构
- RuntimeException:运行时异常,编译器不检查(如 NullPointerException)。
- CheckedException:被检查异常,必须处理或声明抛出(如 IOException)。
- Error:严重错误,程序无法修复(如 OutOfMemoryError)。
1.25 OOM 与 SOF 常见情况
- OOM:堆溢出(对象过多)、栈溢出(递归过深)、元空间溢出(类加载过多)。
- SOF:递归太深或死循环导致栈容量超限。
1.26 线程、程序、进程概念
- 程序:静态代码文件。
- 进程:程序的一次执行,动态,占用资源。
- 线程:进程内的执行单元,轻量级,共享进程资源。
1.27 线程状态
新建、可运行、运行、阻塞(等待、同步、其他)、死亡。
1.28 Java IO 流
- 流向:输入/输出。
- 单元:字节/字符。
- 角色:节点/处理。
- 基类:InputStream/Reader, OutputStream/Writer。
1.29 反射的作用与原理
运行时获取类信息并调用方法。用于 JDBC、框架(Hibernate/Struts)。优点灵活,缺点性能低、破坏封装。可通过 setAccessible(true) 优化。
1.30 List, Set, Map 区别
- List:有序,可重复。
- Set:无序,不可重复。
- Map:键值对,Key 不可重复。
二、JVM 篇
2.1 JVM 内存模型
- 线程独占:栈、本地方法栈、程序计数器。
- 线程共享:堆、方法区。
2.2 内存区域详解
- 栈:存储局部变量、操作栈等。方法入栈出栈。
- 本地方法栈:Native 方法服务。
- 程序计数器:记录当前执行的字节码行号。
- 堆:存放对象实例,GC 主要区域。分新生代、老年代。
- 方法区:类信息、常量、静态变量。JDK 1.8 后为元空间。
2.3 类加载与卸载
- 过程:加载、验证、准备、解析、初始化。
- 双亲委派:委托父加载器,保证核心 API 安全。
- 回收:永久代/元空间满会触发 Full GC。
2.4 垃圾回收算法
- 标记 - 清除:标记后清除,有碎片。
- 复制:新生代常用,无碎片,浪费空间。
- 标记 - 压缩:老年代常用,整理碎片。
- G1/ZGC:现代收集器,追求低停顿。
2.5 堆和栈的区别
- 功能:栈存局部变量,堆存对象。
- 共享:栈私有,堆共享。
- 异常:栈满抛 StackOverflowError,堆满抛 OutOfMemoryError。
2.6 触发 Full GC 的情况
- 旧生代空间不足。
- 永久代/元空间满。
- CMS 出现 promotion failed 或 concurrent mode failure。
- Minor GC 晋升平均大小大于剩余空间。
2.7 为什么 Java 平台无关
JVM 屏蔽了底层硬件差异,执行字节码。源文件编译为字节码,由 JVM 解释或 JIT 编译执行。
2.8 对象分配规则
优先 Eden 区,大对象直接进入老年代,长期存活进入老年代,动态年龄判断,空间分配担保。
2.9 对象创建过程
检查常量池 -> 分配内存(指针碰撞/空闲列表/TLAB)-> 初始化零值 -> 设置对象头。
2.10 判断对象回收
- 引用计数:简单但有循环引用问题。
- 可达性分析:从 GC Roots 向下搜索,不可达即回收。
2.11 JDK 1.8 元空间变动
移除永久代,使用 Native 内存的元空间。默认无限,受系统内存限制。
三、多线程&并发篇
3.1 实现多线程的方法
- 继承 Thread 类。
- 实现 Runnable 接口。
- 实现 Callable 接口(配合 FutureTask)。
- 使用线程池(ExecutorService)。
3.2 停止线程
推荐设置退出标志或使用 interrupt。stop/suspend 已废弃,不安全。
3.3 notify() 和 notifyAll()
- notify:唤醒一个等待线程,可能导致死锁。
- notifyAll:唤醒所有,更安全。wait 应配合 while 循环检查条件。
3.4 sleep() 和 wait() 区别
- sleep:Thread 类,不释放锁,时间到自动恢复。
- wait:Object 类,释放锁,需 notify 唤醒。
3.5 volatile 关键字
保证可见性和禁止指令重排序。不保证原子性。适用于状态标记和单例模式双重检锁。
3.6 start() 和 run() 区别
start() 启动新线程,run() 只是普通方法调用。
3.7 synchronized 原理
底层依赖 monitor 对象。JDK 1.6 后引入偏向锁、轻量级锁、自旋锁等优化。字节码指令为 monitorenter/monitorexit。
3.8 synchronized 使用方式
- 修饰实例方法:锁定当前对象实例。
- 修饰静态方法:锁定当前类 Class 对象。
- 修饰代码块:指定锁定对象。
3.9 线程池理解
- 好处:降低资源消耗,提高响应速度,提高可管理性。
- 核心参数:corePoolSize, maximumPoolSize, keepAliveTime, workQueue 等。
3.10 线程池创建
- 构造 ThreadPoolExecutor。
- Executors 工具类(Fixed, Cached, Single, Scheduled)。
3.11 submit() 和 execute() 区别
execute() 无返回值,submit() 返回 Future 对象,可获取结果或异常。
3.12 Synchronized vs ReentrantLock
- synchronized:关键字,JVM 实现,自动释放锁,非公平。
- ReentrantLock:API,手动 lock/unlock,支持公平锁、中断等待、多条件变量。
3.13 线程安全定义
多线程访问同一代码,结果与单线程一致。Vector 是线程安全的,ArrayList 不是。
3.14 单例模式(双重检锁)
public class Singleton {
private volatile static Singleton uniqueInstance;
private Singleton() {}
public static Singleton getInstance() {
if (uniqueInstance == null) {
synchronized (Singleton.class) {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
}
}
return uniqueInstance;
}
}
volatile 防止指令重排,确保对象初始化完成后再赋值。
四、Spring 篇
4.1 IOC 和 AOP
- IOC:控制反转,依赖注入。容器管理对象生命周期和依赖关系。工厂模式体现。
- AOP:面向切面,分离横切关注点(日志、事务)。代理模式体现(JDK/CGLIB)。
4.2 @Autowired 和 @Resource 区别
- @Autowired:Spring 注解,按类型注入,可配 required=false。
- @Resource:J2EE 标准,默认按名称注入,可指定 name/type。
4.3 依赖注入方式
- 构造器注入(推荐)。
- Setter 方法注入。
- 接口注入(较少用)。
4.4 Spring MVC 流程
DispatcherServlet -> HandlerMapping -> HandlerAdapter -> Controller -> ModelAndView -> ViewResolver -> View -> Response。
4.5 Spring Bean 生命周期
实例化 -> 属性注入 -> Aware 接口回调 -> BeanPostProcessor 前置 -> InitializingBean/init-method -> BeanPostProcessor 后置 -> 销毁 DisposableBean/destroy-method。
4.6 Bean 作用域
singleton(默认), prototype, request, session, global-session。
五、MyBatis 篇
5.1 MyBatis 简介
半 ORM 框架,关注 SQL 本身,灵活度高,减少 JDBC 冗余代码。
5.2 #{} 和 ${} 区别
- #{}:预编译(PreparedStatement),防 SQL 注入。
- ${}:字符串替换,有注入风险。
5.3 字段名与属性名不一致
- SQL 别名映射。
- resultMap 配置映射。
5.4 批量插入
开启 batch 模式 sqlSession,循环 insert 后 commit。
5.5 延迟加载
CGLIB 代理,调用关联对象时触发查询。配置 lazyLoadingEnabled=true。
六、SpringBoot 篇
6.1 什么是 Spring Boot
简化 Spring 应用开发,约定大于配置。内嵌 Tomcat,无需 WAR 部署,自动配置。
6.2 核心注解
@SpringBootApplication,组合了 @Configuration, @EnableAutoConfiguration, @ComponentScan。
6.3 Starters 是什么
启动器,集成依赖包。如 spring-boot-starter-web。
6.4 热部署
Spring Loaded 或 Spring Boot DevTools。
6.5 配置文件加载顺序
命令行 > 环境变量 > jar 包外配置 > jar 包内配置 > 默认值。application 为主,bootstrap 用于配置中心。
相关免费在线工具
- Keycode 信息
查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
- Escape 与 Native 编解码
JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
- JavaScript / HTML 格式化
使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
- JavaScript 压缩与混淆
Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
- 加密/解密文本
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
- Base64 字符串编码/解码
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online