跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
Javajava算法

Java 核心技术面试题与原理详解

Java 面试涵盖基础语法、集合框架、多线程并发、JVM 内存模型、Spring 框架原理及数据库优化等核心领域。内容深入 HashMap 底层结构、线程池参数配置、类加载机制及双亲委派模型,结合代码示例讲解单例模式、AOP 动态代理与事务管理细节。旨在帮助开发者理解底层原理,掌握高频考点与实际应用场景,提升技术深度与实战能力。

CodeArtist发布于 2026/3/15更新于 2026/6/1218 浏览

一、Java 基础语法与核心特性

1. Java 的核心特性有哪些?

答案:

  • 跨平台性(Write Once, Run Anywhere):通过 JVM(Java 虚拟机)实现,字节码文件可在任意支持 JVM 的操作系统运行;
  • 面向对象(OOP):封装、继承、多态三大核心特性;
  • 安全性:支持沙箱机制、字节码校验、权限控制(如文件 IO 权限);
  • 健壮性:自动垃圾回收(GC)避免内存泄漏,强类型检查、异常处理机制减少运行时错误;
  • 分布式:支持 RMI(远程方法调用)、HTTP 协议,便于开发分布式应用;
  • 多线程:内置多线程 API,支持并发编程。
2. 基本数据类型与包装类的区别?

答案:

维度基本数据类型(如 int、float)包装类(如 Integer、Float)
本质原始值,无对象属性引用类型,继承 Object 类
默认值有(如 int 默认 0,boolean 默认 false)无,默认 null
适用场景简单运算、局部变量,效率高集合框架(如 List)、泛型、需要 null 值的场景
缓存机制无部分包装类(Integer[-128~127]、Byte、Short 等)有常量池缓存

关键考点:

  • 自动装箱/拆箱:Java 5+ 特性,编译器自动完成基本类型与包装类的转换(如 int i = new Integer(10)→拆箱,Integer j = 10→装箱);
  • 缓存陷阱:Integer a = 127; Integer b = 127; → a == b为 true(复用缓存);Integer c = 128; Integer d = 128; → c == d为 false(新建对象),需用 equals() 比较值。
3. String、StringBuffer、StringBuilder 的区别?

答案: 核心差异在于可变性和线程安全:

  • String:不可变(底层是 final 修饰的 char 数组/JDK9+ byte 数组),每次修改都会创建新对象,效率低;
  • StringBuffer:可变,线程安全(方法加 synchronized 锁),适用于多线程环境的字符串拼接;
  • StringBuilder:可变,线程不安全,效率高于 StringBuffer,适用于单线程环境的字符串拼接。

底层原理: String 的不可变性源于 private final char value[](JDK8),final 修饰数组引用不可变,且数组无暴露修改接口;StringBuffer 和 StringBuilder 继承 AbstractStringBuilder,底层是可变 char 数组,扩容机制为:默认初始容量 16,当长度超过容量时,新容量=原容量×2+2,不足则直接扩容到所需长度。

4. final 关键字的三种用法?

答案:

  • 修饰类:类不可被继承(如 String、Math),子类无法扩展其功能;
  • 修饰方法:方法不可被重写,可防止子类修改父类核心逻辑;
  • 修饰变量:变量不可被重新赋值(基本类型:值不可变;引用类型:引用地址不可变,但对象内容可修改)。

易错点: final int[] arr = {1,2,3}; arr[0] = 4; 合法(数组内容可变);arr = new int[5]; 非法(引用地址不可变)。

5. 接口(Interface)与抽象类(Abstract Class)的区别?

答案:

维度接口(Interface)抽象类(Abstract Class)
继承方式多实现(一个类可实现多个接口)单继承(一个类只能继承一个抽象类)
成员变量只能是 public static final 常量可包含普通变量、静态变量、常量
成员方法JDK8 前:只能是抽象方法;JDK8+:支持 default/static 方法;JDK9+:支持 private 方法可包含抽象方法、普通方法、静态方法
构造方法无有(不能实例化,供子类调用)
设计目的定义行为规范,解耦(如 List 接口)定义类的模板,复用代码(如 HttpServlet)

应用场景:

  • 接口:不同类需统一行为但实现不同(如 Runnable 接口);
  • 抽象类:同类组件共享核心逻辑(如 AbstractList 封装 List 的公共方法)。
6. Java 异常体系的核心结构?

答案:

  • 顶层父类:Throwable,包含两个核心子类:
    1. Error:严重错误(如 OutOfMemoryError、StackOverflowError),程序无法恢复,无需捕获;
    2. Exception:可处理的异常,分为:
      • 受检异常(Checked Exception):编译时必须捕获(如 IOException、SQLException);
      • 非受检异常(Unchecked Exception):运行时异常(如 NullPointerException、ArrayIndexOutOfBoundsException),继承自 RuntimeException,无需强制捕获。

异常处理关键字:

  • try:包裹可能抛出异常的代码;
  • catch:捕获并处理异常(可多个 catch,按异常子类→父类顺序);
  • finally:无论是否抛出异常,都会执行(常用于关闭资源,如流、数据库连接);
  • throw:手动抛出异常(如 throw new IllegalArgumentException("参数非法"));
  • throws:声明方法可能抛出的异常,告知调用者。

最佳实践:

  • 避免捕获 Throwable(包含 Error,无法处理);
  • 不要忽略异常(空 catch 块);
  • 优先使用 try-with-resources 自动关闭资源(JDK7+,支持实现 AutoCloseable 接口的类)。

二、Java 集合框架

1. 集合框架的核心接口与继承关系?

答案: Java 集合框架核心分为两大体系(均位于 java.util 包):

  • 单列集合(Collection):存储单个元素,核心子接口:
    • List:有序、可重复(如 ArrayList、LinkedList、Vector);
    • Set:无序、不可重复(如 HashSet、TreeSet、LinkedHashSet);
  • 双列集合(Map):存储键值对(key-value),核心实现类 HashMap、TreeMap、LinkedHashMap、ConcurrentHashMap。

关键特性:

  • List:支持索引访问,可通过 get(int index) 获取元素;
  • Set:基于 equals() 和 hashCode() 保证元素唯一性;
  • Map:key 不可重复(重复会覆盖 value),value 可重复;JDK8+ 中 Map 提供 forEach()、computeIfAbsent() 等便捷方法。
2. ArrayList 与 LinkedList 的区别?

答案:

维度ArrayList(数组实现)LinkedList(双向链表实现)
底层结构动态数组(Object[])双向链表(每个节点存储 prev、next、value)
访问效率随机访问快(O(1)),通过索引直接定位随机访问慢(O(n)),需遍历链表
增删效率尾部增删快(O(1)),中间增删慢(需移动数组元素,O(n))中间增删快(O(1),只需修改节点指针),尾部增删需遍历到末尾(O(n),可通过 last 指针优化)
内存占用连续内存,占用少(无额外指针开销)非连续内存,每个节点有额外指针开销
线程安全不安全不安全

应用场景:

  • ArrayList:频繁查询、少量增删(如数据展示列表);
  • LinkedList:频繁中间增删、队列/栈实现(如消息队列)。
3. HashMap 的底层实现原理(JDK1.7 vs JDK1.8)?

答案: HashMap 是基于'哈希表'的 Map 实现,核心是'数组 + 链表/红黑树'的结构,目的是平衡查询和增删效率。

JDK1.7 实现:
  • 底层:数组(Entry[])+ 单向链表;
  • 存储流程:
    1. 计算 key 的 hashCode() → 经过哈希扰动(hashCode() ^ (hashCode() >>> 16))得到哈希值;
    2. 哈希值 & 数组长度 -1 → 定位数组索引(保证索引在数组范围内);
    3. 若索引位置无元素,直接存储;若有元素(哈希冲突),采用'头插法'插入链表。
JDK1.8 优化:
  • 底层:数组(Node[])+ 单向链表 + 红黑树(链表长度≥8 且数组长度≥64 时,链表转为红黑树;链表长度≤6 时,红黑树转回链表);
  • 存储流程:哈希扰动逻辑不变,哈希冲突时采用'尾插法'插入链表(避免 JDK1.7 头插法导致的链表循环问题);
  • 其他优化:
    • 扩容机制:默认初始容量 16,负载因子 0.75,当元素个数≥容量×负载因子时,触发扩容(新容量=原容量×2);
    • 支持 null key 和 null value(null key 的 hash 值为 0,存储在数组索引 0 位置)。

哈希冲突解决:

  • 哈希扰动:减少哈希值的高位忽略问题,提升哈希分布均匀性;
  • 链地址法:冲突元素以链表/红黑树形式存储在同一索引位置。

线程安全问题: HashMap 线程不安全,多线程环境下可能出现:

  • JDK1.7:扩容时头插法导致链表循环;
  • JDK1.8:put 操作可能覆盖数据。 解决方案:使用 ConcurrentHashMap 或 Collections.synchronizedMap(new HashMap<>())。
4. ConcurrentHashMap 的线程安全实现(JDK1.7 vs JDK1.8)?

答案: ConcurrentHashMap 是 HashMap 的线程安全版本,核心差异在于锁机制:

JDK1.7 实现:
  • 底层:Segment 数组 + HashEntry 数组 + 链表;
  • 锁机制:分段锁(Segment 继承 ReentrantLock),每个 Segment 对应一把锁,仅锁定当前 Segment,支持多线程并发访问不同 Segment,提高并发度(默认 Segment 数量 16,支持 16 个线程并发)。
JDK1.8 优化:
  • 底层:Node 数组 + 链表 + 红黑树(与 HashMap 结构一致);
  • 锁机制:放弃分段锁,采用'CAS + synchronized'实现线程安全:
    • 无冲突时:CAS 操作原子性插入元素;
    • 有冲突时:synchronized 锁定当前链表/红黑树的头节点,仅锁定冲突节点所在的链表/树,并发度更高;
  • 其他优化:支持 computeIfAbsent()、forEach() 等原子操作,性能优于 JDK1.7。
5. HashSet 的实现原理?

答案: HashSet 底层依赖 HashMap 实现,核心逻辑:

  • HashSet 的构造方法会创建一个 HashMap 实例;
  • 存储元素时:add(E e) → 调用 HashMap 的 put(e, PRESENT),其中 PRESENT 是一个静态空 Object(仅占位,不存储实际值);
  • 元素唯一性:依赖 HashMap 的 key 不可重复特性(通过 equals() 和 hashCode() 判断);
  • 特性:无序、不可重复、线程不安全,查询/增删效率 O(1)(无哈希冲突时)。

关键考点: 自定义对象作为 HashSet 元素时,必须重写 equals() 和 hashCode(),否则无法保证唯一性(默认使用 Object 类的方法,比较对象地址)。重写原则:

  • 两个对象 equals() 返回 true → hashCode() 必须相等;
  • 两个对象 hashCode() 相等 → equals() 不一定返回 true(哈希冲突)。

三、Java 多线程与并发

1. Java 创建线程的三种方式?

答案:

方式 1:继承 Thread 类,重写 run() 方法(线程执行逻辑),调用 start() 方法启动线程(底层调用 start0() native 方法创建操作系统线程);

class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println("Thread running");
    }
}
// 启动
new MyThread().start();

方式 2:实现 Runnable 接口,重写 run() 方法,将实例传入 Thread 类启动;

class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("Runnable running");
    }
}
// 启动
new Thread(new MyRunnable()).start();

方式 3:实现 Callable 接口,重写 call() 方法(支持返回值和抛出异常),通过 FutureTask 包装后传入 Thread 启动;

class MyCallable implements Callable<String> {
    @Override
    public String call() throws Exception {
        return "Callable result";
    }
}
// 启动
FutureTask<String> future = new FutureTask<>(new MyCallable());
new Thread(future).start();
String result = future.get(); // 获取返回值(阻塞直到线程完成)

对比:

  • 继承 Thread:无法继承其他类(Java 单继承),代码简单;
  • 实现 Runnable/Callable:可继承其他类,支持多线程共享资源,Callable 支持返回值和异常处理。
2. 线程的生命周期与状态转换?

答案: Java 线程有 6 种状态(定义在 Thread.State 枚举中),状态转换如下:

  • NEW:线程创建后未启动(未调用 start());
  • RUNNABLE:线程启动后,处于可运行状态(包含操作系统的'运行中'和'就绪');
  • BLOCKED:线程等待同步锁(如 synchronized 未获取锁时);
  • WAITING:线程无限期等待(如调用 Object.wait()、Thread.join()、LockSupport.park(),需其他线程唤醒);
  • TIMED_WAITING:线程限时等待(如调用 Thread.sleep(ms)、Object.wait(ms)、Thread.join(ms),超时自动唤醒);
  • TERMINATED:线程执行完成或异常终止。

核心转换路径: NEW → RUNNABLE(start()) → TERMINATED(执行完成); RUNNABLE → BLOCKED(竞争锁失败) → RUNNABLE(获取锁); RUNNABLE → WAITING/TIMED_WAITING(调用等待方法) → RUNNABLE(被唤醒/超时)。

3. synchronized 与 Lock 的区别?

答案:

维度synchronized(内置锁)Lock(显式锁,如 ReentrantLock)
锁实现JVM 层面实现(C++ 代码)JDK 层面实现(Java 代码)
锁获取与释放自动获取(进入同步块)、自动释放(退出同步块/异常)手动获取(lock())、手动释放(unlock(),需在 finally 中执行)
锁类型可重入锁、非公平锁(默认),JDK6+ 支持偏向锁/轻量级锁/重量级锁升级可重入锁,支持公平锁/非公平锁(构造函数指定)
功能扩展无(仅支持基础同步)支持中断锁(lockInterruptibly())、超时锁(tryLock(ms))、条件变量(Condition)、读写锁(ReentrantReadWriteLock)
性能JDK6+ 优化后,性能接近 Lock高并发场景下性能更优,灵活度高

应用场景:

  • synchronized:简单同步场景(如单例模式、简单方法同步),代码简洁,无需手动管理锁;
  • Lock:复杂并发场景(如超时获取锁、中断锁、读写分离),如缓存系统、分布式锁实现。
4. volatile 关键字的作用?

答案: volatile 是 Java 提供的轻量级同步机制,核心作用有两个:

  1. 保证可见性:一个线程修改 volatile 变量后,其他线程能立即看到最新值(禁止 CPU 缓存,变量读写直接操作主内存);
  2. 禁止指令重排序:编译器和 CPU 会对指令重排序优化,volatile 通过内存屏障(Memory Barrier)阻止重排序(如 DCL 单例模式中,volatile 修饰实例变量防止指令重排导致的空指针)。

局限性:

  • 不保证原子性:如 volatile int i = 0; i++; 非原子操作(包含读取、加 1、写入三步),多线程下可能出现计数错误,需配合 synchronized 或 AtomicInteger 使用;
  • 不能替代锁:仅适用于'单写多读'或'状态标记'场景(如 volatile boolean flag = false; 控制线程启停)。

经典应用:双重校验锁(DCL)单例模式:

public class Singleton {
    // volatile 禁止指令重排,防止 instance 未初始化完成就被其他线程获取
    private static volatile Singleton instance;
    
    private Singleton() {}
    
    public static Singleton getInstance() {
        if (instance == null) {
            // 第一次校验(无锁,提高效率)
            synchronized (Singleton.class) {
                // 加锁
                if (instance == null) {
                    // 第二次校验(防止多线程并发创建)
                    instance = new Singleton(); // 禁止重排:分配内存→初始化→赋值
                }
            }
        }
        return instance;
    }
}
5. 线程池的核心参数与工作原理?

答案: Java 线程池核心类是 ThreadPoolExecutor,基于'池化思想'减少线程创建/销毁开销,提高并发效率。

核心参数(构造方法):
public ThreadPoolExecutor(
    int corePoolSize,      // 核心线程数(常驻线程,即使空闲也不销毁)
    int maximumPoolSize,   // 最大线程数(核心线程 + 临时线程的总上限)
    long keepAliveTime,    // 临时线程空闲时间(超过则销毁)
    TimeUnit unit,         // keepAliveTime 的时间单位
    BlockingQueue<Runnable> workQueue, // 任务阻塞队列(核心线程满时,任务入队)
    ThreadFactory threadFactory,       // 线程创建工厂(自定义线程名称、优先级等)
    RejectedExecutionHandler handler   // 拒绝策略(队列和最大线程数都满时,处理新任务)
)
工作原理:
  1. 提交任务时,若核心线程数未满,创建核心线程执行任务;
  2. 核心线程满时,任务加入阻塞队列;
  3. 队列满时,若未达到最大线程数,创建临时线程执行任务;
  4. 临时线程空闲时间超过 keepAliveTime,销毁临时线程;
  5. 队列和最大线程数都满时,执行拒绝策略。
常见拒绝策略:
  • AbortPolicy(默认):直接抛出 RejectedExecutionException;
  • CallerRunsPolicy:由提交任务的线程(调用者)执行任务;
  • DiscardPolicy:直接丢弃新任务,无异常;
  • DiscardOldestPolicy:丢弃队列中最旧的任务,加入新任务。
常见线程池(Executors 工具类):
  • Executors.newFixedThreadPool(n):固定核心线程数和最大线程数(n),队列无界(LinkedBlockingQueue);
  • Executors.newCachedThreadPool():核心线程数 0,最大线程数 Integer.MAX_VALUE,临时线程空闲 60 秒销毁,队列同步移交(SynchronousQueue);
  • Executors.newSingleThreadExecutor():核心线程数 1,最大线程数 1,队列无界,保证任务串行执行;
  • Executors.newScheduledThreadPool(n):核心线程数 n,支持定时/延迟执行任务(ScheduledFutureTask)。

注意:阿里巴巴 Java 开发手册禁止使用 Executors 创建线程池,原因是:

  • newFixedThreadPool/newSingleThreadExecutor:队列无界,可能导致 OOM;
  • newCachedThreadPool:最大线程数无界,可能创建大量线程导致 CPU/内存耗尽。 推荐直接使用 ThreadPoolExecutor 构造方法,指定合理参数(如核心线程数=CPU 核心数±1,队列使用有界队列)。
6. ThreadLocal 的原理与内存泄漏问题?

答案: ThreadLocal 是线程本地存储工具,允许每个线程拥有独立的变量副本,避免多线程共享变量的并发问题。

原理:
  • 底层结构:每个 Thread 对象持有一个 ThreadLocalMap(ThreadLocal 的内部类),ThreadLocalMap 的 key 是 ThreadLocal 实例(弱引用),value 是线程本地变量副本;
  • 核心方法:
    • set(T value):获取当前线程的 ThreadLocalMap,将(当前 ThreadLocal 实例,value)存入;
    • get():获取当前线程的 ThreadLocalMap,根据当前 ThreadLocal 实例获取 value,无则调用 initialValue() 初始化;
    • remove():删除当前线程的 ThreadLocalMap 中对应的键值对。
内存泄漏问题:
  • 原因:ThreadLocalMap 的 key 是弱引用(WeakReference<ThreadLocal<?>>),当 ThreadLocal 实例被回收(如外部引用置 null),key 会变成 null,而 value 是强引用,若线程未结束(如线程池核心线程),value 无法被 GC 回收,导致内存泄漏;
  • 解决方案:
    1. 用完 ThreadLocal 后调用 remove() 方法删除 value;
    2. 避免使用静态 ThreadLocal(生命周期长,易导致内存泄漏);
    3. 线程池场景下,确保任务执行完成后清理 ThreadLocal 变量。

应用场景:

  • 存储线程上下文信息(如用户登录信息、数据库连接、事务对象);
  • 避免方法参数传递(如 Spring 的 RequestContextHolder 底层使用 ThreadLocal 存储 HttpServletRequest)。

四、JVM 核心原理

1. JVM 内存模型(运行时数据区)?

答案: JVM 运行时数据区分为 5 个部分(基于 JDK8):

  • 1. 程序计数器(Program Counter Register):

    • 作用:存储当前线程执行的字节码指令地址(行号),线程切换时恢复执行位置;
    • 特点:线程私有(每个线程一个),无 OOM 风险(唯一不会抛出 OutOfMemoryError 的区域)。
  • 2. 虚拟机栈(VM Stack):

    • 作用:存储线程执行方法时的栈帧(包含局部变量表、操作数栈、方法出口等);
    • 特点:线程私有,栈帧入栈(方法调用)和出栈(方法返回)对应方法执行生命周期;
    • 异常:栈深度超过 JVM 限制→StackOverflowError(如递归调用无终止);栈扩展时内存不足→OutOfMemoryError。
  • 3. 本地方法栈(Native Method Stack):

    • 作用:与虚拟机栈类似,仅支持 Native 方法(如 Thread.start0())的执行;
    • 特点:线程私有,可能抛出 StackOverflowError 和 OutOfMemoryError。
  • 4. 堆(Heap):

    • 作用:存储对象实例和数组,是 JVM 内存最大的区域,也是 GC 的主要区域;
    • 特点:线程共享,可通过 -Xms(初始堆大小)、-Xmx(最大堆大小)配置;
    • 分区(逻辑划分):
      • 年轻代(Young Generation):分为 Eden 区、Survivor0(S0)区、Survivor1(S1)区,比例默认 8:1:1;
      • 老年代(Old Generation):存储存活时间长的对象(年轻代对象多次 GC 后存活则进入老年代);
      • 元空间(Metaspace,JDK8+):替代永久代,存储类元信息(类名、方法信息、字段信息),使用本地内存,默认无大小限制(可通过 -XX:MetaspaceSize、-XX:MaxMetaspaceSize 配置)。
    • 异常:堆内存不足→OutOfMemoryError: Java heap space;元空间不足→OutOfMemoryError: Metaspace。
  • 5. 方法区(Method Area):

    • 作用:存储类元信息、常量池(String 常量池 JDK7+ 移至堆)、静态变量、即时编译后的代码;
    • 特点:线程共享,JDK8 前为永久代(PermGen),JDK8 后被元空间替代。
2. 垃圾回收(GC)的核心原理?

答案: GC 是 JVM 自动回收堆中无用对象(无引用的对象)的过程,核心目标是释放内存,避免内存泄漏。

1. 垃圾判定算法:
  • 引用计数法:给对象添加引用计数器,引用 +1,引用失效 -1,计数器为 0 则判定为垃圾;缺点:无法解决循环引用(如 A 引用 B,B 引用 A,计数器均为 1,无法回收);
  • 可达性分析算法(JVM 采用):以'GC Roots'为起点,遍历对象引用链,不可达的对象判定为垃圾;
    • GC Roots 包括:虚拟机栈局部变量表中的引用、本地方法栈中的引用、方法区静态变量引用、常量池引用、活跃线程的引用。
2. 常见 GC 算法:
  • 标记 - 清除算法(Mark-Sweep):
    • 步骤:标记垃圾对象→清除垃圾对象;
    • 优点:简单高效;
    • 缺点:产生内存碎片,后续大对象分配可能失败。
  • 复制算法(Copying):
    • 步骤:将内存分为两块(如 Eden 和 S0/S1),标记存活对象→复制到另一块内存,清除原内存;
    • 优点:无内存碎片,分配效率高;
    • 缺点:内存利用率低(仅 50%),适合年轻代(存活对象少)。
  • 标记 - 整理算法(Mark-Compact):
    • 步骤:标记存活对象→将存活对象向内存一端移动→清除另一端垃圾;
    • 优点:无内存碎片,内存利用率高;
    • 缺点:移动对象成本高,适合老年代(存活对象多)。
  • 分代收集算法(JVM 采用):
    • 原理:根据对象存活时间划分代(年轻代、老年代),不同代采用不同 GC 算法;
    • 年轻代:存活对象少,采用复制算法;
    • 老年代:存活对象多,采用标记 - 清除或标记 - 整理算法。
3. 常见 GC 收集器:
  • Serial 收集器:单线程 GC,年轻代采用复制算法,老年代采用标记 - 整理算法,适合单 CPU 环境(如客户端应用);
  • Parallel Scavenge 收集器:多线程 GC,年轻代复制算法,追求高吞吐量(吞吐量=运行用户代码时间/(运行用户代码时间+GC 时间)),适合服务器应用;
  • ParNew 收集器:Parallel Scavenge 的多线程版本,支持与 CMS 收集器配合;
  • CMS 收集器(Concurrent Mark Sweep):老年代 GC,基于标记 - 清除算法,并发收集(与用户线程同时执行),追求低延迟,适合响应时间敏感的应用(如 Web 应用);缺点:产生内存碎片、并发开销大;
  • G1 收集器(Garbage-First):JDK9+ 默认 GC,基于标记 - 整理算法,将堆划分为多个大小相等的 Region,优先回收垃圾多的 Region,兼顾吞吐量和低延迟,支持大堆内存(如数十 GB);
  • ZGC/Shenandoah 收集器:新一代低延迟 GC,暂停时间控制在毫秒级以下,支持 TB 级堆内存。
3. 类加载机制与双亲委派模型?

答案: 类加载是将.class 字节码文件加载到 JVM 内存,生成 Class 对象的过程,核心分为 5 个阶段:

1. 类加载流程:
  • 加载(Loading):通过类加载器读取.class 文件,生成二进制字节流,在堆中创建 Class 对象;
  • 验证(Verification):校验字节码合法性(如文件格式、语法、语义、符号引用验证),防止恶意字节码;
  • 准备(Preparation):为类静态变量分配内存并设置默认值(如 int 默认 0,boolean 默认 false),不包含实例变量;
  • 解析(Resolution):将符号引用(如类名、方法名)转换为直接引用(内存地址);
  • 初始化(Initialization):执行类构造器 <clinit>() 方法(静态变量赋值 + 静态代码块执行),初始化顺序:父类→子类,静态变量→静态代码块。
2. 类加载器分类:
  • 启动类加载器(Bootstrap ClassLoader):C++ 实现,加载 JDK 核心类库(如 rt.jar),无父加载器;
  • 扩展类加载器(Extension ClassLoader):Java 实现,加载 jre/lib/ext 目录下的类库;
  • 应用程序类加载器(Application ClassLoader):Java 实现,加载应用 classpath 下的类库(默认类加载器);
  • 自定义类加载器(Custom ClassLoader):继承 ClassLoader 类,重写 findClass() 方法,用于加载自定义路径的类(如热部署、加密类)。
3. 双亲委派模型:
  • 核心规则:类加载器加载类时,先委托父加载器加载,父加载器无法加载(找不到类)时,才由自身加载;
  • 流程:应用程序类加载器→扩展类加载器→启动类加载器(顶层),若启动类加载器无法加载,反向逐级尝试加载;
  • 作用:
    1. 避免类重复加载(如 java.lang.String 仅由启动类加载器加载一次);
    2. 保护核心类库(防止自定义 java.lang.String 类替换核心类)。
  • 破坏双亲委派模型的场景:
    • 热部署(如 OSGi 框架):需要不同模块加载同一类的不同版本;
    • JNDI、SPI 机制(如 JDBC 驱动加载):核心类由启动类加载器加载,需加载应用 classpath 下的驱动类,通过线程上下文类加载器(Thread Context ClassLoader)实现。

五、Spring 核心框架

1. Spring IoC 的原理与实现?

答案: IoC(Inversion of Control,控制反转)是 Spring 的核心思想,指将对象的创建、依赖注入(DI)的控制权从应用程序转移到 Spring 容器,实现解耦。

核心概念:
  • IoC 容器:Spring 的核心组件(如 ApplicationContext、BeanFactory),负责管理 Bean 的生命周期(创建、初始化、销毁)和依赖关系;
  • Bean:IoC 容器管理的对象(如 Service、Dao 层对象);
  • 依赖注入(DI):IoC 的具体实现,容器在创建 Bean 时自动注入其依赖的其他 Bean(无需手动 new 对象)。
依赖注入的三种方式:

字段注入:直接在字段上添加 @Autowired 注解,代码简洁,但不推荐(无法通过构造方法校验依赖,不利于单元测试);

@Service
public class UserService {
    @Autowired
    private UserDao userDao;
}

Setter 方法注入:通过 Setter 方法注入依赖,适用于可选依赖;

@Service
public class UserService {
    private UserDao userDao;
    
    @Autowired
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
}

构造方法注入:通过 Bean 的构造方法传入依赖,推荐使用(强制依赖,避免空指针);

@Service
public class UserService {
    private final UserDao userDao;
    
    // 构造方法注入(@Autowired 可省略,Spring 4.3+ 支持)
    public UserService(UserDao userDao) {
        this.userDao = userDao;
    }
}
IoC 容器初始化流程:
  1. 加载配置文件(如 XML、注解 @Configuration);
  2. 解析配置,扫描 Bean 定义(如 @Component、@Service、@Repository),注册到 BeanDefinitionRegistry;
  3. 实例化 Bean(默认单例,懒加载除外);
  4. 依赖注入(DI):通过 BeanPostProcessor(后置处理器)自动注入依赖;
  5. 初始化 Bean:执行 @PostConstruct 注解方法、InitializingBean 接口的 afterPropertiesSet() 方法、自定义 init-method;
  6. Bean 就绪,供应用程序调用;
  7. 容器关闭时,销毁 Bean:执行 @PreDestroy 注解方法、DisposableBean 接口的 destroy() 方法、自定义 destroy-method。
2. Spring AOP 的原理与应用?

答案: AOP(Aspect-Oriented Programming,面向切面编程)是 Spring 的核心特性,通过'横切'机制,将日志、事务、权限等通用功能(切面)与业务逻辑解耦,实现代码复用。

核心概念:
  • 切面(Aspect):封装通用功能的类(如日志切面、事务切面),包含通知和切入点;
  • 通知(Advice):切面的具体逻辑(如日志打印、事务提交),分为 5 种类型:
    • @Before:目标方法执行前执行;
    • @After:目标方法执行后执行(无论是否异常);
    • @AfterReturning:目标方法正常返回后执行;
    • @AfterThrowing:目标方法抛出异常后执行;
    • @Around:环绕目标方法执行(可控制目标方法的执行与否,如事务的开始和提交);
  • 切入点(Pointcut):定义切面作用的目标方法(如'所有 Service 层的方法'),通过表达式(如 execution 表达式)指定;
  • 连接点(JoinPoint):目标方法的执行点(如方法调用、异常抛出),是切入点的具体实例;
  • 织入(Weaving):将切面逻辑融入目标方法的过程,Spring AOP 默认采用动态代理织入。
实现原理:

Spring AOP 基于动态代理实现,分为两种代理方式:

  1. JDK 动态代理:

    • 适用场景:目标类实现接口;
    • 原理:通过 java.lang.reflect.Proxy 类动态生成代理类,代理类实现目标接口,并重写目标方法,在方法中织入切面逻辑;
    • 缺点:仅支持接口代理,无法代理无接口的类。
  2. CGLIB 动态代理:

    • 适用场景:目标类未实现接口;
    • 原理:通过 CGLIB(Code Generation Library)字节码生成框架,动态生成目标类的子类,重写目标方法,织入切面逻辑;
    • 优点:支持任意类代理(无需接口),性能优于 JDK 动态代理(创建代理类开销大,但执行效率高)。
应用场景:
  • 日志记录:记录方法调用参数、返回值、执行时间;
  • 事务管理:控制事务的开始、提交、回滚(Spring 声明式事务基于 AOP 实现);
  • 权限校验:方法执行前校验用户权限;
  • 异常处理:统一捕获目标方法的异常并处理。
示例:日志切面
// 切面类
@Aspect
@Component
public class LogAspect {
    // 切入点:所有 com.example.service 包下的 public 方法
    @Pointcut("execution(public * com.example.service..*(..))")
    public void servicePointcut() {}
    
    // 环绕通知
    @Around("servicePointcut()")
    public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
        // 目标方法执行前:打印请求参数
        String methodName = joinPoint.getSignature().getName();
        Object[] args = joinPoint.getArgs();
        System.out.println("方法" + methodName + "调用,参数:" + Arrays.toString(args));
        
        long start = System.currentTimeMillis();
        Object result = joinPoint.proceed(); // 执行目标方法
        
        // 目标方法执行后:打印返回值和执行时间
        long cost = System.currentTimeMillis() - start;
        System.out.println("方法" + methodName + "返回值:" + result + ",执行时间:" + cost + "ms");
        
        return result;
    }
}
3. Spring 事务管理的原理?

答案: Spring 事务管理核心是'声明式事务'(基于 AOP)和'编程式事务'(手动编码),其中声明式事务是主流用法。

1. 事务的 ACID 特性:
  • 原子性(Atomicity):事务是不可分割的最小单位,要么全部执行,要么全部回滚;
  • 一致性(Consistency):事务执行前后,数据完整性保持一致(如转账前后总金额不变);
  • 隔离性(Isolation):多个事务并发执行时,事务之间相互隔离,互不影响;
  • 持久性(Durability):事务提交后,数据修改永久生效(写入磁盘)。
2. 事务隔离级别(Spring 支持):
  • DEFAULT:默认隔离级别(依赖数据库,如 MySQL 默认 REPEATABLE READ);
  • READ_UNCOMMITTED:读未提交,最低隔离级别,可能出现脏读、不可重复读、幻读;
  • READ_COMMITTED:读已提交,避免脏读,可能出现不可重复读、幻读(如 Oracle 默认);
  • REPEATABLE_READ:可重复读,避免脏读、不可重复读,可能出现幻读(如 MySQL 默认);
  • SERIALIZABLE:串行化,最高隔离级别,避免所有并发问题,性能最低。
3. 事务传播行为(核心,解决事务嵌套问题):

Spring 定义了 7 种传播行为,常用的有:

  • REQUIRED(默认):如果当前存在事务,加入事务;如果没有事务,创建新事务;
  • REQUIRES_NEW:无论当前是否存在事务,都创建新事务(新事务与原事务相互独立,原事务暂停);
  • SUPPORTS:如果当前存在事务,加入事务;如果没有事务,以非事务方式执行;
  • NOT_SUPPORTED:以非事务方式执行,如果当前存在事务,暂停原事务;
  • NEVER:以非事务方式执行,如果当前存在事务,抛出异常。
4. 声明式事务实现(基于 AOP):
  • 配置方式:通过 @EnableTransactionManagement 注解启用事务管理(Spring Boot 自动启用);
  • 核心注解:@Transactional(标注在类或方法上,类级别的注解对所有方法生效);
  • 原理:
    1. @Transactional 注解被解析为切面,切入点是标注该注解的方法;
    2. 通知逻辑:通过 AOP 动态代理,在目标方法执行前开启事务,执行后提交事务,异常时回滚事务;
    3. 事务管理器:Spring 通过 PlatformTransactionManager 接口适配不同数据库(如 DataSourceTransactionManager 适配 JDBC,HibernateTransactionManager 适配 Hibernate)。
5. 事务失效的常见场景:
  • 方法非 public 修饰(@Transactional 仅对 public 方法生效);
  • 事务方法内部调用(如 A 方法调用本类的 B 方法,B 方法的 @Transactional 失效,因为未经过代理类);
  • 异常类型不匹配(默认仅捕获 RuntimeException 和 Error,checked 异常需通过 rollbackFor 指定);
  • 手动捕获异常未抛出(如 try-catch 异常但未 throw,事务无法感知异常,不会回滚);
  • 传播行为配置错误(如 NOT_SUPPORTED、NEVER);
  • 数据源未配置事务管理器(PlatformTransactionManager 未被 Spring 管理)。

六、数据库与 MyBatis

1. JDBC 的核心操作步骤?

答案: JDBC(Java Database Connectivity)是 Java 访问数据库的标准 API,核心步骤如下:

  1. 加载数据库驱动(JDK8+ 无需手动加载,DriverManager 自动扫描);
  2. 建立数据库连接(通过 DriverManager.getConnection(url, username, password));
  3. 创建 Statement/PreparedStatement 对象(执行 SQL 语句);
  4. 执行 SQL(executeQuery() 查询,executeUpdate() 增删改);
  5. 处理结果集(查询时通过 ResultSet 遍历结果);
  6. 关闭资源(ResultSet、Statement、Connection,需在 finally 中关闭,避免资源泄漏)。

示例代码:

public void queryUser() {
    Connection conn = null;
    PreparedStatement pstmt = null;
    ResultSet rs = null;
    try {
        // 1. 加载驱动(MySQL 8.0+ 驱动类:com.mysql.cj.jdbc.Driver)
        Class.forName("com.mysql.cj.jdbc.Driver");
        
        // 2. 建立连接
        String url = "jdbc:mysql://localhost:3306/test?useSSL=false&serverTimezone=UTC";
        conn = DriverManager.getConnection(url, "root", "123456");
        
        // 3. 创建 PreparedStatement(预编译 SQL,防止 SQL 注入)
        String sql = "SELECT id, name FROM user WHERE id = ?";
        pstmt = conn.prepareStatement(sql);
        pstmt.setInt(1, 1); // 设置参数
        
        // 4. 执行查询
        rs = pstmt.executeQuery();
        
        // 5. 处理结果集
        while (rs.next()) {
            int id = rs.getInt("id");
            String name = rs.getString("name");
            System.out.println("id: " + id + ", name: " + name);
        }
    } catch (ClassNotFoundException | SQLException e) {
        e.printStackTrace();
    } finally {
        // 6. 关闭资源(逆序关闭)
        try {
            if (rs != null) rs.close();
            if (pstmt != null) pstmt.close();
            if (conn != null) conn.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

关键考点:

  • PreparedStatement vs Statement:PreparedStatement 支持预编译 SQL、参数化查询,防止 SQL 注入,性能更优;Statement 不支持参数化,存在 SQL 注入风险;
  • SQL 注入:如 SELECT * FROM user WHERE + name + "'",若 name 传入 ' OR '1'='1,则 SQL 变为 SELECT * FROM user WHERE OR '1'='1',查询所有用户;PreparedStatement 通过参数绑定避免该问题。
2. MyBatis 的核心组件与工作原理?

答案: MyBatis 是持久层框架,简化 JDBC 操作,通过 XML 或注解配置 SQL 语句,无需手动编写 JDBC 代码。

核心组件:
  • SqlSessionFactory:MyBatis 核心工厂类,通过 SqlSessionFactoryBuilder 读取配置文件(mybatis-config.xml)创建,线程安全;
  • SqlSession:会话对象,封装数据库连接和事务管理,线程不安全(每次请求创建新实例);
  • Mapper 接口:自定义 DAO 接口,MyBatis 通过动态代理生成实现类,关联 XML/注解中的 SQL;
  • Mapper.xml:配置 SQL 语句、参数映射、结果集映射;
  • Configuration:MyBatis 全局配置对象,存储核心配置(如数据源、事务管理器、Mapper 注册)。
工作原理:
  1. 加载配置文件:SqlSessionFactoryBuilder 读取 mybatis-config.xml 和 Mapper.xml,解析配置信息(数据源、SQL 语句、映射规则);
  2. 创建 SqlSessionFactory:通过解析后的配置信息创建 SqlSessionFactory(单例模式);
  3. 创建 SqlSession:SqlSessionFactory 调用 openSession() 创建 SqlSession,默认不自动提交事务;
  4. 获取 Mapper 代理对象:SqlSession 调用 getMapper(Mapper 接口.class),通过动态代理生成 Mapper 接口的实现类;
  5. 执行 SQL:调用 Mapper 接口方法,MyBatis 根据方法名匹配 Mapper.xml 中的 SQL 语句,执行 JDBC 操作;
  6. 处理结果集:MyBatis 自动将 ResultSet 映射为 Java 对象(根据 resultType/resultMap 配置);
  7. 提交/回滚事务:执行完成后,SqlSession 调用 commit() 提交事务或 rollback() 回滚事务;
  8. 关闭 SqlSession:释放资源。
核心配置(mybatis-config.xml):
<configuration>
    <!-- 环境配置(数据源、事务管理器) -->
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <!-- 事务管理类型:JDBC/MANAGED -->
            <dataSource type="POOLED">
                <!-- 数据源类型:POOLED(连接池)/UNPOOLED/JNDI -->
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/test?useSSL=false"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
    <!-- 注册 Mapper.xml -->
    <mappers>
        <mapper resource="com/example/mapper/UserMapper.xml"/>
    </mappers>
</configuration>
Mapper.xml 示例:
<mapper namespace="com.example.mapper.UserMapper">
    <!-- 结果集映射(数据库字段→Java 对象属性) -->
    <resultMap id="UserResultMap" type="com.example.entity.User">
        <id column="id" property="id"/>
        <result column="name" property="name"/>
        <result column="age" property="age"/>
    </resultMap>
    <!-- 查询用户 -->
    <select id="selectUserById" parameterType="int" resultMap="UserResultMap">
        SELECT id, name, age FROM user WHERE id = #{id}
    </select>
    <!-- 新增用户 -->
    <insert id="insertUser" parameterType="com.example.entity.User">
        INSERT INTO user (name, age) VALUES (#{name}, #{age})
    </insert>
</mapper>
3. MyBatis 的一级缓存与二级缓存?

答案: MyBatis 提供缓存机制,减少数据库查询次数,提升性能,分为一级缓存和二级缓存。

一级缓存(SqlSession 级别,默认开启):
  • 作用范围:同一个 SqlSession 内,多次执行相同的 SQL 查询(参数相同),仅第一次查询数据库,后续从缓存获取结果;
  • 实现原理:SqlSession 内部维护一个 HashMap,key 为缓存键(由 SQL 语句、参数、RowBounds、环境等组成),value 为查询结果;
  • 失效场景:
    • 执行 insert/update/delete 操作(会清空一级缓存);
    • 调用 SqlSession.clearCache() 手动清空;
    • SqlSession 关闭或提交事务。
二级缓存(Mapper 级别,默认关闭):
  • 作用范围:同一个 Mapper 接口(命名空间)下,多个 SqlSession 共享缓存;
  • 启用方式:
    1. 在 mybatis-config.xml 中开启全局缓存(默认开启,可省略):<setting name="cacheEnabled" value="true"/>;
    2. 在 Mapper.xml 中添加 <cache/> 标签(启用当前 Mapper 的二级缓存);
  • 实现原理:每个 Mapper 接口对应一个 Cache 对象,SqlSession 查询后将结果存入二级缓存,其他 SqlSession 查询相同 SQL 时,先从二级缓存获取;
  • 注意事项:
    • 缓存的对象必须实现 Serializable 接口(二级缓存可能序列化存储);
    • 执行 insert/update/delete 操作会清空当前 Mapper 的二级缓存;
    • 可通过 useCache="false"(查询语句)或 flushCache="true"(增删改语句)控制缓存行为。

缓存查询顺序:二级缓存 → 一级缓存 → 数据库。

七、设计模式与性能优化

1. 单例模式的几种实现方式与线程安全?

答案: 单例模式确保一个类仅有一个实例,并提供全局访问点,常用实现方式如下:

1. 饿汉式(线程安全,非懒加载):
public class Singleton {
    // 类加载时初始化实例(饿汉式)
    private static final Singleton instance = new Singleton();
    
    // 私有构造方法,禁止外部实例化
    private Singleton() {}
    
    // 提供全局访问方法
    public static Singleton getInstance() {
        return instance;
    }
}
  • 优点:简单高效,类加载时初始化,天然线程安全;
  • 缺点:非懒加载,类加载时即创建实例,若实例未被使用,浪费内存。
2. 懒汉式(线程不安全→线程安全优化):
  • 优点:懒加载(使用时才创建实例),线程安全,性能优;
  • 关键:volatile 关键字必须加,防止 instance = new Singleton() 指令重排(分配内存→初始化→赋值),导致其他线程获取到未初始化的实例。

优化版(双重校验锁 DCL,线程安全,懒加载):

public class Singleton {
    // volatile 禁止指令重排
    private static volatile Singleton instance;
    
    private Singleton() {}
    
    public static Singleton getInstance() {
        if (instance == null) {
            // 第一次校验(无锁,提高效率)
            synchronized (Singleton.class) {
                // 加锁
                if (instance == null) {
                    // 第二次校验(防止多线程并发创建)
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

基础版(线程不安全,多线程下可能创建多个实例):

public class Singleton {
    private static Singleton instance;
    
    private Singleton() {}
    
    // 线程不安全:多线程同时进入 if 条件,创建多个实例
    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}
3. 静态内部类式(线程安全,懒加载,推荐):
public class Singleton {
    private Singleton() {}
    
    // 静态内部类,类加载时不初始化
    private static class SingletonHolder {
        private static final Singleton instance = new Singleton();
    }
    
    // 调用 getInstance() 时,才加载 SingletonHolder,初始化实例
    public static Singleton getInstance() {
        return SingletonHolder.instance;
    }
}
  • 优点:懒加载(静态内部类按需加载),线程安全(类加载机制保证),代码简洁,无锁开销;
  • 原理:静态内部类的加载时机是在第一次被引用时,类加载过程是线程安全的,确保实例仅创建一次。
4. 枚举式(线程安全,防反射/序列化,最佳实践):
public enum Singleton {
    INSTANCE;
    
    // 枚举类的方法
    public void doSomething() {
        System.out.println("Singleton enum");
    }
}
  • 优点:
    1. 线程安全:枚举类的实例在类加载时创建,天然线程安全;
    2. 防反射:枚举类的构造方法被编译器私有化,无法通过反射创建实例;
    3. 防序列化:枚举类默认实现 Serializable,序列化时不会创建新实例;
  • 缺点:非懒加载,类加载时即创建实例。
2. Java 性能优化的常见手段?

答案: Java 性能优化需从'代码层面、JVM 层面、数据库层面、架构层面'多维度入手,核心目标是提升响应速度、降低资源消耗。

1. 代码层面优化:
  • 集合使用优化:
    • ArrayList 初始化时指定初始容量(避免频繁扩容);
    • 频繁增删用 LinkedList,频繁查询用 ArrayList;
    • 避免在循环中使用 ArrayList.add(index, element)(O(n) 复杂度);
  • 字符串优化:
    • 频繁拼接用 StringBuilder(单线程)/StringBuffer(多线程),避免 String 拼接(创建大量临时对象);
    • 常量字符串用 String.intern() 复用常量池对象;
  • 循环优化:
    • 减少循环内的对象创建(如 for (int i = 0; i < list.size(); i++) → 先获取 size:int size = list.size(); for (int i = 0; i < size; i++));
    • 避免循环内的复杂计算(如方法调用、表达式计算);
  • 避免空指针:使用 Objects.requireNonNull()、Optional 类,减少 null 判断;
  • 资源管理:使用 try-with-resources 自动关闭流、数据库连接,避免资源泄漏。
2. JVM 层面优化:
  • 堆内存配置:合理设置 -Xms(初始堆)和 -Xmx(最大堆),建议两者相等(避免频繁扩容),堆大小一般为物理内存的 1/2~1/3;
  • 年轻代优化:调整 -XX:NewRatio(年轻代与老年代比例,默认 2:1)、-XX:SurvivorRatio(Eden 与 S0/S1 比例,默认 8:1),根据应用对象存活时间调整;
  • GC 收集器选择:
    • 高吞吐量场景:使用 Parallel Scavenge 收集器;
    • 低延迟场景:使用 G1/ZGC 收集器;
  • 逃逸分析:启用 -XX:+DoEscapeAnalysis(默认启用),JVM 自动分析对象是否逃逸,未逃逸的对象可分配在栈上(减少 GC 压力)。
3. 数据库层面优化:
  • 索引优化:给查询频繁的字段建立索引(如 WHERE、JOIN、ORDER BY 字段),避免过度索引(影响增删效率);
  • SQL 优化:
    • 避免 SELECT *,只查询需要的字段;
    • 避免 WHERE 子句中使用函数(如 WHERE DATE(create_time) = '2025-01-01',导致索引失效);
    • 避免 JOIN 过多表(建议不超过 3 张表),大表 JOIN 用分页;
    • 批量操作替代循环单条操作(如 MyBatis 的 batchInsert);
  • 连接池优化:合理设置数据库连接池大小(如 HikariCP 的 maximum-pool-size,建议为 CPU 核心数×2+1),避免连接泄漏。
4. 架构层面优化:
  • 缓存引入:使用 Redis、Ehcache 等缓存热点数据(如用户信息、配置数据),减少数据库查询;
  • 异步处理:将耗时操作(如日志打印、邮件发送)异步化(使用线程池、消息队列),提升响应速度;
  • 负载均衡:通过 Nginx、LVS 等实现多服务器负载均衡,分散请求压力;
  • 分布式部署:将应用拆分为微服务,按业务模块部署,提高并发处理能力。

八、总结

面试时,除了记忆答案,更要理解底层原理(如 HashMap 的哈希冲突解决、Spring AOP 的动态代理、JVM 的 GC 机制),并结合项目经验说明实际应用场景(如线程池在项目中的配置、事务失效的排查过程)。建议重点掌握多线程并发、JVM、Spring 核心原理等高级考点,这些是区分初级与中高级开发者的关键。

目录

  1. 一、Java 基础语法与核心特性
  2. 1. Java 的核心特性有哪些?
  3. 2. 基本数据类型与包装类的区别?
  4. 3. String、StringBuffer、StringBuilder 的区别?
  5. 4. final 关键字的三种用法?
  6. 5. 接口(Interface)与抽象类(Abstract Class)的区别?
  7. 6. Java 异常体系的核心结构?
  8. 二、Java 集合框架
  9. 1. 集合框架的核心接口与继承关系?
  10. 2. ArrayList 与 LinkedList 的区别?
  11. 3. HashMap 的底层实现原理(JDK1.7 vs JDK1.8)?
  12. JDK1.7 实现:
  13. JDK1.8 优化:
  14. 4. ConcurrentHashMap 的线程安全实现(JDK1.7 vs JDK1.8)?
  15. JDK1.7 实现:
  16. JDK1.8 优化:
  17. 5. HashSet 的实现原理?
  18. 三、Java 多线程与并发
  19. 1. Java 创建线程的三种方式?
  20. 2. 线程的生命周期与状态转换?
  21. 3. synchronized 与 Lock 的区别?
  22. 4. volatile 关键字的作用?
  23. 5. 线程池的核心参数与工作原理?
  24. 核心参数(构造方法):
  25. 工作原理:
  26. 常见拒绝策略:
  27. 常见线程池(Executors 工具类):
  28. 6. ThreadLocal 的原理与内存泄漏问题?
  29. 原理:
  30. 内存泄漏问题:
  31. 四、JVM 核心原理
  32. 1. JVM 内存模型(运行时数据区)?
  33. 2. 垃圾回收(GC)的核心原理?
  34. 1. 垃圾判定算法:
  35. 2. 常见 GC 算法:
  36. 3. 常见 GC 收集器:
  37. 3. 类加载机制与双亲委派模型?
  38. 1. 类加载流程:
  39. 2. 类加载器分类:
  40. 3. 双亲委派模型:
  41. 五、Spring 核心框架
  42. 1. Spring IoC 的原理与实现?
  43. 核心概念:
  44. 依赖注入的三种方式:
  45. IoC 容器初始化流程:
  46. 2. Spring AOP 的原理与应用?
  47. 核心概念:
  48. 实现原理:
  49. 应用场景:
  50. 示例:日志切面
  51. 3. Spring 事务管理的原理?
  52. 1. 事务的 ACID 特性:
  53. 2. 事务隔离级别(Spring 支持):
  54. 3. 事务传播行为(核心,解决事务嵌套问题):
  55. 4. 声明式事务实现(基于 AOP):
  56. 5. 事务失效的常见场景:
  57. 六、数据库与 MyBatis
  58. 1. JDBC 的核心操作步骤?
  59. 2. MyBatis 的核心组件与工作原理?
  60. 核心组件:
  61. 工作原理:
  62. 核心配置(mybatis-config.xml):
  63. Mapper.xml 示例:
  64. 3. MyBatis 的一级缓存与二级缓存?
  65. 一级缓存(SqlSession 级别,默认开启):
  66. 二级缓存(Mapper 级别,默认关闭):
  67. 七、设计模式与性能优化
  68. 1. 单例模式的几种实现方式与线程安全?
  69. 1. 饿汉式(线程安全,非懒加载):
  70. 2. 懒汉式(线程不安全→线程安全优化):
  71. 3. 静态内部类式(线程安全,懒加载,推荐):
  72. 4. 枚举式(线程安全,防反射/序列化,最佳实践):
  73. 2. Java 性能优化的常见手段?
  74. 1. 代码层面优化:
  75. 2. JVM 层面优化:
  76. 3. 数据库层面优化:
  77. 4. 架构层面优化:
  78. 八、总结
  • 💰 8折买阿里云服务器限时8折了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • 嵌入式系统 Newlib 编译指南
  • 基于 STM32F407 与 K230 的二维云台激光打靶系统设计
  • 【2026机器人新产品】稚晖君/智元上纬:启元Q1
  • WebSocket 与 WebRTC:Web 实时通信与音视频通信实战
  • LLaMA 系列模型演进:从 Llama-1 到 Llama-3 的技术发展与对比
  • Java 运算符详解:从基础算术到位运算实战
  • Android AMS 核心数据结构解析:TaskRecord 与内存回收
  • 基于 AI 辅助开发工具构建 SpringBoot 在线图书借阅平台
  • Spring Cloud 微服务架构概述与工程搭建实战
  • PyCharm 集成 AI 插件配置指南:OpenAI 与 DeepSeek
  • 工业物联网时序数据库选型:InfluxDB 与 Apache IoTDB 对比
  • 常见字符编码方式详解
  • Midjourney AI 绘图工具使用指南与基础操作教程
  • POJ 2748 全排列算法:递归与回溯详解
  • 腾讯 AI 智能体对比:QClaw 与 WorkBuddy
  • C++ Linux 环境下内存泄漏检测方式
  • Windows 11 与 Ubuntu 22.04 双系统安装指南
  • 2026 主流 AI 智能体平台 OpenClaw 厂商产品深度横评
  • 网页抓取(Web Scraping)技术指南:从原理到实战
  • 基于 DeepFace 与 OpenCV 的实时情绪分析器

相关免费在线工具

  • 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

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online