Java 核心高频考点(面试必问,含答案+原理)

张开发
2026/4/14 10:45:03 15 分钟阅读

分享文章

Java 核心高频考点(面试必问,含答案+原理)
一、Java 基础(初级必问)1. JDK、JRE、JVM 区别JVM:Java 虚拟机,负责执行字节码,跨平台核心。Java 代码编译后生成 .class 字节码,JVM 负责将字节码翻译成对应操作系统的机器指令,实现“一次编译,到处运行”,不同系统有不同的 JVM 实现(如 Windows 版、Linux 版),但执行逻辑一致。JRE:Java 运行环境 = JVM + 核心类库(如 java.lang 包、java.util 包等)。如果只需要运行 Java 程序,安装 JRE 即可,无需 JDK。JDK:Java 开发工具包 = JRE + 编译器(javac) + 开发工具(如 javadoc、jdb 调试工具等)。开发 Java 程序必须安装 JDK,因为需要用 javac 编译代码。2. == 和 equals() 区别==:是运算符,分两种场景:基本类型(int、char、double 等):比较值是否相等,比如 1 == 1 为 true,1 == 2 为 false。引用类型(对象、数组等):比较内存地址是否相等,即判断两个引用是否指向同一个对象,比如 new String("a") == new String("a") 为 false(两个对象,地址不同)。equals():是 Object 类的方法,默认实现和 == 一致(比较地址),但很多类(String、Integer、ArrayList 等)重写了该方法,改为比较内容:示例:"a".equals("a") 为 true(内容相同),new String("a").equals(new String("a")) 也为 true(String 重写后比较内容)。注意:使用 equals() 前,建议先判断对象是否为 null,避免空指针异常(如 obj != null obj.equals(xxx))。3. String、StringBuffer、StringBuilderString:不可变字符串(底层是 final 修饰的 char 数组,JDK9 后改为 byte 数组)。不可变意味着每次修改 String(如拼接、替换)都会新建一个 String 对象,频繁修改效率低,但线程安全(不可变对象天然线程安全)。StringBuffer:可变字符串,底层是 char 数组,线程安全(方法加了 synchronized 锁),适合多线程环境下的字符串修改,效率中等(锁的开销)。StringBuilder:可变字符串,底层是 char 数组,非线程安全(无锁),单线程环境下修改效率最高,是日常开发(单线程)的首选。4. 装箱与拆箱装箱:基本类型 → 包装类(自动转换,JDK5+ 特性),比如 int → Integer,底层调用 Integer.valueOf(int) 方法。拆箱:包装类 → 基本类型(自动转换),比如 Integer → int,底层调用 Integer.intValue() 方法。高频坑:Integer 缓存范围为 -128 ~ 127。当装箱的值在这个范围内时,会复用缓存中的对象,超出范围则会新建对象。示例:Integer a = 127; Integer b = 127; a == b 为 true(复用缓存);Integer c = 128; Integer d = 128; c == d 为 false(新建对象)。5. 接口 vs 抽象类接口(interface):只能定义抽象方法(JDK8+ 支持默认方法 default 和静态方法 static),方法默认修饰符为 public abstract(可省略)。无构造器,不能实例化,一个类可以实现多个接口(多实现)。核心作用:定义行为规范,实现解耦(比如 List 接口,ArrayList、LinkedList 有不同实现,但都遵循 List 的行为)。抽象类(abstract class):可以定义普通方法(带方法体)和抽象方法(abstract 修饰,无方法体)。有构造器(用于子类继承时初始化),不能实例化,一个类只能继承一个抽象类(单继承)。核心作用:模板设计,将子类共有的逻辑提取到抽象类中,子类只需实现抽象方法即可。二、集合框架(初级,中级)1. List 集合ArrayList:底层是动态数组(Object[] 数组),查询快(通过索引直接访问,时间复杂度 O(1)),增删慢(需要移动数组元素,时间复杂度 O(n)),线程不安全,适合查询频繁、增删少的场景。LinkedList:底层是双向链表,增删快(只需修改链表节点的指针,时间复杂度 O(1)),查询慢(需要从头/尾遍历,时间复杂度 O(n)),线程不安全,适合增删频繁、查询少的场景。Vector:底层是数组,线程安全(方法加了 synchronized 锁),效率极低,几乎被淘汰,日常开发优先用 ArrayList + 手动加锁/线程安全集合替代。2. Set 集合HashSet:底层依赖 HashMap 实现(存值作为 HashMap 的 key,value 是一个固定的空对象),无序(插入顺序和遍历顺序不一致),无重复元素,允许 null,查询、增删效率高(时间复杂度 O(1))。TreeSet:底层是红黑树(平衡二叉树),有序(默认按自然排序,也可自定义比较器),无重复元素,不允许 null,查询、增删效率中等(时间复杂度 O(log n)),适合需要排序的场景。去重原理:Set 集合判断元素是否重复,先调用元素的 hashCode() 方法获取哈希值,若哈希值不同,则元素不同;若哈希值相同,再调用 equals() 方法判断内容,内容相同则视为重复元素,不会存入。3. Map 集合(必考)HashMap(必问到底)数据结构:数组 + 链表 + 红黑树(JDK8 及以后),JDK7 及以前是数组 + 链表。核心原理:数组(哈希桶):存储键值对节点(Node),数组下标由 key 的 hashCode() 经过哈希算法计算得出。链表:解决哈希冲突(不同 key 计算出相同下标),将冲突的节点串联成链表。红黑树:当链表长度 ≥ 8 且数组长度 ≥ 64 时,链表转为红黑树(红黑树是平衡二叉树,查询效率更高,O(log n));当链表节点 ≤ 6 时,红黑树退化为链表(减少红黑树的维护开销)。关键参数:初始容量:16(默认值),容量必须是 2 的幂(方便哈希计算,减少冲突)。加载因子:0.75(默认值),当数组中元素个数(size)≥ 容量 × 加载因子时,触发扩容(容量翻倍,重新计算所有节点的

更多文章