Java面试题及详细答案120道之(081-100)

前后端面试题》专栏集合了前后端各个知识模块的面试题,包括html,javascript,css,vue,react,java,Openlayers,leaflet,cesium,mapboxGL,threejs,nodejs,mangoDB,MySQL,Linux... 。

前后端面试题-专栏总目录

文章目录

  • 一、本文面试题目录
      • [81. Java中的`ConcurrentHashMap`与`HashMap`在并发场景下有什么区别?](#81. Java中的ConcurrentHashMapHashMap在并发场景下有什么区别?)
      • [82. 解释Java中的`JIT`编译](#82. 解释Java中的JIT编译)
      • [83. Java中的`try-catch-finally`中`return`的执行顺序是什么?](#83. Java中的try-catch-finallyreturn的执行顺序是什么?)
      • [84. 什么是Java中的`Record`(记录类)?](#84. 什么是Java中的Record(记录类)?)
      • [85. Java中的`Arrays.asList()`返回的列表有什么特点?](#85. Java中的Arrays.asList()返回的列表有什么特点?)
      • [86. Java中的`synchronized`关键字的实现原理(JDK 6+的优化)](#86. Java中的synchronized关键字的实现原理(JDK 6+的优化))
      • [87. 什么是Java中的`模式匹配(Pattern Matching)`?](#87. 什么是Java中的模式匹配(Pattern Matching)?)
      • [88. Java中的`@FunctionalInterface`注解有什么作用?](#88. Java中的@FunctionalInterface注解有什么作用?)
      • [89. 解释Java中的`内存泄漏`及常见场景](#89. 解释Java中的内存泄漏及常见场景)
      • [90. 什么是Java的反射机制?有哪些常见应用场景?](#90. 什么是Java的反射机制?有哪些常见应用场景?)
      • [91. Java中的异常体系结构是怎样的?`Checked Exception`和`Unchecked Exception`有何区别?](#91. Java中的异常体系结构是怎样的?Checked ExceptionUnchecked Exception有何区别?)
      • [92. `try-catch-finally`中,如果`finally`有`return`,`try`或`catch`中的`return`会生效吗?](#92. try-catch-finally中,如果finallyreturntrycatch中的return会生效吗?)
      • [93. 什么是线程安全?如何实现线程安全?](#93. 什么是线程安全?如何实现线程安全?)
      • [94. `synchronized`和`Lock`的区别是什么?](#94. synchronizedLock的区别是什么?)
      • [95. 什么是死锁?如何避免死锁?](#95. 什么是死锁?如何避免死锁?)
      • [96. Java中的线程池有哪些核心参数?`ThreadPoolExecutor`的工作原理是什么?](#96. Java中的线程池有哪些核心参数?ThreadPoolExecutor的工作原理是什么?)
      • [97. Java中的`volatile`关键字有什么作用?它能保证原子性吗?](#97. Java中的volatile关键字有什么作用?它能保证原子性吗?)
      • [98. 什么是Java内存模型(JMM)?它解决了什么问题?](#98. 什么是Java内存模型(JMM)?它解决了什么问题?)
      • [99. `ArrayList`和`LinkedList`的区别是什么?各自的适用场景?](#99. ArrayListLinkedList的区别是什么?各自的适用场景?)
      • [100. `HashMap`的底层实现原理是什么?JDK1.7和JDK1.8有何区别?](#100. HashMap的底层实现原理是什么?JDK1.7和JDK1.8有何区别?)
  • 二、120道面试题目录列表

一、本文面试题目录

81. Java中的ConcurrentHashMapHashMap在并发场景下有什么区别?

原理

  • HashMap:非线程安全,并发修改可能导致ConcurrentModificationException
  • ConcurrentHashMap(JDK 8+):线程安全,采用"CAS + 同步块"实现,支持高并发读写,效率优于HashTable

核心区别

  • 锁粒度:ConcurrentHashMap锁桶(链表/红黑树),HashTable锁整个表;
  • 迭代器:ConcurrentHashMap的迭代器弱一致性(不抛异常),HashMap的迭代器快速失败。

代码示例

java 复制代码
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class ConcurrentMapDemo {
    public static void main(String[] args) throws InterruptedException {
        Map<String, Integer> map = new ConcurrentHashMap<>();
        
        // 多线程并发写入
        Runnable task = () -> {
            for (int i = 0; i < 1000; i++) {
                map.put(Thread.currentThread().getName() + i, i);
            }
        };
        
        Thread t1 = new Thread(task);
        Thread t2 = new Thread(task);
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        
        System.out.println("map大小:" + map.size()); // 输出2000(无并发问题)
    }
}

82. 解释Java中的JIT编译

原理 :JIT(即时编译)是JVM的优化技术,将热点代码(频繁执行的代码)从字节码编译为机器码,提高执行效率(字节码解释执行慢)。
关键概念

  • 解释执行:字节码逐条翻译为机器码,启动快但执行慢;
  • 编译执行:提前将字节码编译为机器码,执行快但启动慢;
  • 混合模式:JVM默认模式,结合两者优势(热点代码编译,其他解释)。

代码示例(热点代码触发JIT):

java 复制代码
public class JITDemo {
    // 热点方法(被频繁调用)
    public static int add(int a, int b) {
        return a + b;
    }
    
    public static void main(String[] args) {
        // 频繁调用add(),触发JIT编译
        for (int i = 0; i < 10_000_000; i++) {
            add(i, i + 1);
        }
    }
}

83. Java中的try-catch-finallyreturn的执行顺序是什么?

原理finally块始终执行(除非JVM退出),若trycatch中有return,会先执行finally,再返回结果(finally中的return会覆盖之前的返回值)。

代码示例

java 复制代码
public class TryCatchFinally {
    public static int test() {
        try {
            System.out.println("try块");
            return 1; // 先暂存返回值1,执行finally后返回
        } catch (Exception e) {
            return 2;
        } finally {
            System.out.println("finally块");
            // return 3; // 若打开此行,最终返回3(覆盖try的return)
        }
    }
    
    public static void main(String[] args) {
        System.out.println("结果:" + test());
        // 输出:try块 → finally块 → 结果:1
    }
}

84. 什么是Java中的Record(记录类)?

原理 :JDK 16引入的Record,用于简化"数据载体"类(仅含字段和访问方法),自动生成equals()hashCode()toString()和构造器。
特点 :不可变(字段final),不能继承其他类(可实现接口)。

代码示例

java 复制代码
// 记录类:自动生成getter、equals、hashCode、toString
public record Point(int x, int y) {
    // 可定义静态方法或构造器
    public Point { // 紧凑构造器(无参数列表)
        if (x < 0 || y < 0) {
            throw new IllegalArgumentException("坐标不能为负");
        }
    }
    
    public static Point origin() { // 静态方法
        return new Point(0, 0);
    }
}

public class RecordDemo {
    public static void main(String[] args) {
        Point p = new Point(3, 4);
        System.out.println(p.x()); // 自动生成的getter(无get前缀)
        System.out.println(p); // 输出Point[x=3, y=4](自动生成的toString)
    }
}

85. Java中的Arrays.asList()返回的列表有什么特点?

原理Arrays.asList()返回java.util.Arrays.ArrayList(内部类),而非java.util.ArrayList,特点:

  • 长度固定(不可增删元素,否则抛UnsupportedOperationException);
  • 底层是原数组的视图(修改列表元素会同步修改原数组);
  • 不支持null元素(针对基本类型数组的包装类)。

代码示例

java 复制代码
import java.util.Arrays;
import java.util.List;

public class AsListDemo {
    public static void main(String[] args) {
        String[] arr = {"a", "b", "c"};
        List<String> list = Arrays.asList(arr);
        
        // 修改列表元素 → 原数组同步修改
        list.set(0, "x");
        System.out.println(arr[0]); // 输出x
        
        // list.add("d"); // 抛出UnsupportedOperationException(长度固定)
        
        // 转换为可修改的ArrayList
        List<String> mutableList = new java.util.ArrayList<>(list);
        mutableList.add("d"); // 成功
    }
}

86. Java中的synchronized关键字的实现原理(JDK 6+的优化)

原理synchronized通过锁机制保证同步,JDK 6+引入锁升级优化,避免性能损耗:

  1. 偏向锁:单线程访问时,仅记录线程ID,无竞争时无需加锁;
  2. 轻量级锁:多线程交替访问,通过CAS尝试获取锁,避免重量级锁开销;
  3. 重量级锁:多线程竞争激烈时,使用操作系统互斥量,性能较差。

代码示例(同步方法与同步块):

java 复制代码
public class SynchronizedDemo {
    // 同步方法(锁为当前对象)
    public synchronized void syncMethod() {
        // 同步代码
    }
    
    // 同步块(锁为指定对象)
    public void syncBlock() {
        Object lock = new Object();
        synchronized (lock) {
            // 同步代码
        }
    }
}

87. 什么是Java中的模式匹配(Pattern Matching)

原理 :JDK 16+引入的语法糖,简化类型判断和转换,主要用于instanceofswitch
instanceof模式匹配:判断类型的同时完成转换,避免显式强转。

代码示例

java 复制代码
public class PatternMatching {
    public static void print(Object obj) {
        // 传统方式:先判断再强转
        if (obj instanceof String) {
            String str = (String) obj;
            System.out.println("字符串长度:" + str.length());
        }
        
        // 模式匹配:判断+转换一步完成
        if (obj instanceof String str) { // 变量str仅在if块内有效
            System.out.println("字符串长度:" + str.length());
        }
        
        // switch模式匹配(JDK 17+)
        switch (obj) {
            case Integer i -> System.out.println("整数:" + i);
            case String s -> System.out.println("字符串:" + s);
            default -> System.out.println("未知类型");
        }
    }
}

88. Java中的@FunctionalInterface注解有什么作用?

原理@FunctionalInterface是标记注解,用于编译期检查接口是否为函数式接口(仅含一个抽象方法),若不符合则编译报错,增强代码可读性。

代码示例

java 复制代码
@FunctionalInterface // 正确:仅一个抽象方法
interface MyFunction {
    void doSomething();
    
    default void defaultMethod() {} // 允许默认方法
    static void staticMethod() {} // 允许静态方法
}

// @FunctionalInterface // 编译错误:两个抽象方法
interface InvalidFunction {
    void method1();
    void method2();
}

89. 解释Java中的内存泄漏及常见场景

原理 :内存泄漏指对象不再使用但未被GC回收,导致内存占用持续增加,最终可能引发OutOfMemoryError
常见场景

  • 静态集合持有对象(如static List未清除元素);
  • 未关闭资源(如流、连接未调用close());
  • 匿名内部类持有外部类引用(如线程未终止,外部类无法回收);
  • ThreadLocal未调用remove()(线程池线程复用导致变量残留)。

代码示例(静态集合导致内存泄漏):

java 复制代码
import java.util.ArrayList;
import java.util.List;

public class MemoryLeak {
    // 静态集合持有对象引用
    private static List<Object> list = new ArrayList<>();
    
    public static void addObject(Object obj) {
        list.add(obj); // 对象被静态集合引用,无法回收
    }
    
    public static void main(String[] args) {
        while (true) {
            addObject(new Object()); // 持续添加对象,导致内存泄漏
        }
    }
}

90. 什么是Java的反射机制?有哪些常见应用场景?

答案

反射机制是指程序在运行时可以获取自身的信息(类、方法、字段等),并能动态操作这些信息的能力。通过java.lang.reflect包中的类(如ClassMethodField)实现。

原理

Java编译器将类编译为字节码(.class),运行时JVM加载类并生成Class对象,反射通过该对象访问类的结构。

应用场景

  • 框架开发(如Spring的IOC容器,通过反射实例化Bean);
  • 动态代理(如MyBatis的Mapper接口代理);
  • 注解解析(如JUnit的@Test注解检测)。

代码示例

java 复制代码
public class ReflectionDemo {
    public static void main(String[] args) throws Exception {
        // 获取Class对象
        Class<?> clazz = User.class;
        // 实例化对象
        Object user = clazz.getDeclaredConstructor().newInstance();
        // 获取并设置字段
        Field nameField = clazz.getDeclaredField("name");
        nameField.setAccessible(true); // 访问私有字段
        nameField.set(user, "Alice");
        // 调用方法
        Method getNameMethod = clazz.getMethod("getName");
        String name = (String) getNameMethod.invoke(user);
        System.out.println(name); // 输出:Alice
    }
}

class User {
    private String name;
    public String getName() { return name; }
}
No. 大剑师精品GIS教程推荐
0 地图渲染基础- 【WebGL 教程】 - 【Canvas 教程】 - 【SVG 教程】
1 Openlayers 【入门教程】 - 【源代码+示例 300+】
2 Leaflet 【入门教程】 - 【源代码+图文示例 150+】
3 MapboxGL【入门教程】 - 【源代码+图文示例150+】
4 Cesium 【入门教程】 - 【源代码+综合教程 200+】
5 threejs【中文API】 - 【源代码+图文示例200+】

91. Java中的异常体系结构是怎样的?Checked ExceptionUnchecked Exception有何区别?

答案
异常体系结构

  • 顶层父类为Throwable,分为Error(错误,如OutOfMemoryError,程序无法处理)和Exception(异常,程序可处理)。
  • Exception分为RuntimeException(运行时异常,如NullPointerException)和非运行时异常(如IOException)。

区别

类型 特点 示例
Checked Exception 编译时检查,必须捕获或声明抛出 IOExceptionSQLException
Unchecked Exception 运行时抛出,编译不检查,无需强制处理 NullPointerExceptionIndexOutOfBoundsException

代码示例

java 复制代码
// Checked Exception:必须处理(捕获或声明)
public void readFile() throws IOException { // 声明抛出
    FileReader fr = new FileReader("test.txt");
    fr.read();
}

// Unchecked Exception:无需强制处理
public void divide(int a, int b) {
    if (b == 0) {
        throw new ArithmeticException("除数不能为0"); // 运行时抛出
    }
}

92. try-catch-finally中,如果finallyreturntrycatch中的return会生效吗?

答案

不会。finally块始终执行(除非JVM退出),若finally包含return,会覆盖trycatch中的return值。

代码示例

java 复制代码
public static int test() {
    try {
        return 1;
    } catch (Exception e) {
        return 2;
    } finally {
        return 3; // 覆盖try的return
    }
}

public static void main(String[] args) {
    System.out.println(test()); // 输出:3
}

原理

编译器会将try/catch中的return值暂存,执行finally后,若finallyreturn,则直接返回该值,丢弃暂存值。

93. 什么是线程安全?如何实现线程安全?

答案
线程安全:多线程环境下,多个线程访问共享资源时,无需额外同步操作即可保证结果正确。

实现方式

  1. 同步机制
    • synchronized关键字(修饰方法或代码块,保证原子性、可见性、有序性)。
    • Lock接口(如ReentrantLock,更灵活的锁控制)。
  2. 使用线程安全的类 :如ConcurrentHashMapAtomicInteger
  3. 无状态设计:避免共享变量(如Servlet默认线程不安全,需通过无状态实现安全)。

代码示例(synchronized)

java 复制代码
class Counter {
    private int count = 0;
    // 同步方法,保证线程安全
    public synchronized void increment() {
        count++;
    }
    public int getCount() { return count; }
}

94. synchronizedLock的区别是什么?

答案

特性 synchronized Lock
实现方式 JVM层面的隐式锁 API层面的显式锁(需手动加锁/释放)
灵活性 自动释放锁,无法中断等待线程 可手动释放(unlock()),支持中断、超时获取锁
公平性 非公平锁 可指定公平锁(构造方法参数)
绑定条件 不支持条件变量 支持(Condition),可实现复杂等待/唤醒
性能 JDK1.6后优化(偏向锁、轻量级锁),性能接近Lock 性能更优(高并发下)

代码示例(Lock)

java 复制代码
class LockCounter {
    private int count = 0;
    private Lock lock = new ReentrantLock(); // 显式锁
    public void increment() {
        lock.lock(); // 加锁
        try {
            count++;
        } finally {
            lock.unlock(); // 必须手动释放
        }
    }
}

95. 什么是死锁?如何避免死锁?

答案
死锁:两个或多个线程相互持有对方所需的资源,且都不释放,导致无限等待的状态。

产生条件

  • 互斥:资源不可共享;
  • 持有并等待:线程持有部分资源,等待其他资源;
  • 不可剥夺:资源不可被强制剥夺;
  • 循环等待:线程间形成资源等待循环。

避免方式

  1. 按固定顺序获取资源(打破循环等待);
  2. 限时获取资源(如tryLock(timeout));
  3. 减少锁的持有时间。

死锁示例

java 复制代码
// 线程1持有lock1,等待lock2;线程2持有lock2,等待lock1 → 死锁
Object lock1 = new Object();
Object lock2 = new Object();

new Thread(() -> {
    synchronized (lock1) {
        try { Thread.sleep(100); } catch (InterruptedException e) {}
        synchronized (lock2) { System.out.println("线程1获取lock2"); }
    }
}).start();

new Thread(() -> {
    synchronized (lock2) {
        try { Thread.sleep(100); } catch (InterruptedException e) {}
        synchronized (lock1) { System.out.println("线程2获取lock1"); }
    }
}).start();

96. Java中的线程池有哪些核心参数?ThreadPoolExecutor的工作原理是什么?

答案
ThreadPoolExecutor核心参数

  1. corePoolSize:核心线程数(始终存活,除非设置allowCoreThreadTimeOut)。
  2. maximumPoolSize:最大线程数(核心线程+临时线程)。
  3. keepAliveTime:临时线程空闲超时时间。
  4. workQueue:任务等待队列(如LinkedBlockingQueue)。
  5. threadFactory:线程创建工厂。
  6. handler:拒绝策略(如AbortPolicy:直接抛出异常)。

工作原理

  1. 提交任务时,若核心线程未满,创建核心线程执行任务;
  2. 核心线程满,任务加入等待队列;
  3. 队列满,若未达最大线程数,创建临时线程执行;
  4. 超过最大线程数,触发拒绝策略。

代码示例

java 复制代码
ThreadPoolExecutor executor = new ThreadPoolExecutor(
    2, // 核心线程数
    5, // 最大线程数
    60L, TimeUnit.SECONDS, // 临时线程超时时间
    new LinkedBlockingQueue<>(3), // 等待队列
    Executors.defaultThreadFactory(),
    new ThreadPoolExecutor.AbortPolicy() // 拒绝策略
);

97. Java中的volatile关键字有什么作用?它能保证原子性吗?

答案
作用

  1. 可见性 :一个线程修改volatile变量后,其他线程能立即看到最新值(禁止CPU缓存)。
  2. 有序性:禁止指令重排序(通过内存屏障实现)。

不能保证原子性 :例如i++操作(读取→修改→写入),多线程下可能出现丢失更新。

代码示例(可见性)

java 复制代码
class Flag {
    volatile boolean stop = false; // 保证可见性
    public void run() {
        while (!stop) {
            // 循环执行,直到stop被修改为true
        }
    }
}

原子性问题示例

java 复制代码
class VolatileTest {
    volatile int count = 0;
    public void increment() {
        count++; // 非原子操作,多线程下结果可能不正确
    }
}

98. 什么是Java内存模型(JMM)?它解决了什么问题?

答案
Java内存模型(JMM) :是一种抽象模型,定义了线程和主内存之间的交互规则,解决多线程环境下的可见性、原子性、有序性问题。

核心问题及解决

  • 可见性 :线程对共享变量的修改需立即同步到主内存,其他线程从主内存读取(通过volatilesynchronized实现)。
  • 原子性 :保证操作不可分割(通过synchronizedLock、原子类实现)。
  • 有序性 :禁止指令重排序(通过volatilesynchronizedhappens-before规则)。

JMM抽象结构

  • 线程操作本地内存(CPU缓存),通过主内存交换共享变量。

99. ArrayListLinkedList的区别是什么?各自的适用场景?

答案

特性 ArrayList LinkedList
数据结构 动态数组(连续内存) 双向链表(非连续内存)
随机访问 快(O(1)),通过索引直接访问 慢(O(n)),需遍历链表
增删操作(中间) 慢(O(n),需移动元素) 快(O(1),只需修改指针)
内存占用 较少(仅存储元素) 较多(需存储前后指针)

适用场景

  • ArrayList:频繁随机访问、少量增删(尾部)。
  • LinkedList:频繁增删(中间)、不频繁随机访问。

代码示例

java 复制代码
List<String> arrayList = new ArrayList<>();
arrayList.add("A"); // 尾部添加快
arrayList.get(0); // 随机访问快

List<String> linkedList = new LinkedList<>();
linkedList.add(1, "B"); // 中间插入快
linkedList.remove(0); // 头部删除快

100. HashMap的底层实现原理是什么?JDK1.7和JDK1.8有何区别?

答案
底层原理:基于数组+链表/红黑树实现,通过哈希函数计算键的索引,存储键值对。

JDK1.7 vs JDK1.8区别

特性 JDK1.7 JDK1.8
数据结构 数组+链表 数组+链表+红黑树(链表长度>8时转为树)
哈希冲突解决 头插法(可能导致死锁) 尾插法(避免死锁)
扩容机制 需重新计算哈希值 高低位拆分(减少哈希计算)
存储结构 Entry<K,V> 数组 Node<K,V> 数组(实现Entry接口)
红黑树优化 有(提升查询效率,O(logn)

代码示例(HashMap使用)

java 复制代码
HashMap<String, Integer> map = new HashMap<>();
map.put("a", 1);
map.put("b", 2);
int value = map.get("a"); // 获取值

二、120道面试题目录列表

文章序号 Java面试题120道
1 Java面试题及详细答案120道(01-20)
2 Java面试题及详细答案120道(21-40)
3 Java面试题及详细答案120道(41-60)
4 Java面试题及详细答案120道(61-80)
5 Java面试题及详细答案120道(81-100)
6 Java面试题及详细答案120道(5101-120)
相关推荐
雪人.12 天前
JavaWeb经典面试题
java·服务器·前端·java面试题
还是大剑师兰特14 天前
拥抱AI,还是大剑师兰特2025年博客创作详细总结
人工智能·大剑师·2025博客之星
还是大剑师兰特16 天前
SVG图像文件结构
大剑师·svg图像
还是大剑师兰特17 天前
JEPG图像文件结构
大剑师·jepg结构
还是大剑师兰特17 天前
GIF图像文件结构
大剑师·gif图像结构
还是大剑师兰特18 天前
PNG图像文件结构
服务器·大剑师·png结构
还是大剑师兰特19 天前
单兵作战需要哪些计算能力
大剑师·作战工具
还是大剑师兰特1 个月前
MVC和MVVM模式详解+对比
mvc·mvvm·大剑师
还是大剑师兰特1 个月前
前端设计模式:详解、应用场景与核心对比
前端·设计模式·大剑师
还是大剑师兰特1 个月前
用豆包生成PPT的详细操作步骤
ai·powerpoint·大剑师