当前位置: 首页 > ai >正文

Java面试题及详细答案120道之(041-060)

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

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

在这里插入图片描述

文章目录

  • 一、本文面试题目录
      • 41. 什么是工厂模式?简单工厂、工厂方法、抽象工厂的区别?
      • 42. Java中的泛型有什么作用?
      • 43. Java中的`Comparable`和`Comparator`有何区别?
      • 44. 什么是Java中的注解?
      • 45. Java中的线程池有什么作用?
      • 46. 解释Java中的`双亲委派模型`
      • 47. Java中的字符编码有哪些常见类型,它们有什么区别?
      • 48. 什么是Java中的函数式接口?如何使用Lambda表达式?
      • 49. 简述Java中的泛型擦除机制
      • 50. 什么是Java中的线程局部变量(ThreadLocal)?如何使用?
      • 51. 解释Java中的动态代理及其实现方式
      • 52. 什么是Java中的注解(Annotation)?如何自定义注解?
      • 53. 解释Java中的序列化与反序列化
      • 54. Java中的`equals()`和`==`有什么区别?
      • 55. 什么是Java中的Lambda表达式?适用于什么场景?
      • 56. 解释Java中的Stream API及其常用操作
      • 57. Java中的`volatile`关键字有什么作用?
      • 58. Java中的`try-with-resources`语法有什么作用?
      • 59. 解释Java中的深拷贝与浅拷贝
      • 60. Java中的`String`、`StringBuilder`、`StringBuffer`有什么区别?
  • 二、120道面试题目录列表

一、本文面试题目录

41. 什么是工厂模式?简单工厂、工厂方法、抽象工厂的区别?

答案
工厂模式:用于创建对象,隐藏实例化逻辑,解耦对象创建与使用。

区别

  • 简单工厂:一个工厂类根据参数创建不同产品(违反开闭原则)。

    class CarFactory {public static Car createCar(String type) {if ("Benz".equals(type)) return new Benz();else if ("BMW".equals(type)) return new BMW();return null;}
    }
    
  • 工厂方法:每个产品对应一个工厂类,通过继承扩展(符合开闭原则)。

    interface CarFactory { Car createCar(); }
    class BenzFactory implements CarFactory {public Car createCar() { return new Benz(); }
    }
    class BMWFactory implements CarFactory {public Car createCar() { return new BMW(); }
    }
    
  • 抽象工厂:创建一系列相关产品(产品族),如汽车工厂同时生产汽车和发动机。

42. Java中的泛型有什么作用?

  • 答案:泛型用于在编译时确保类型安全,可将类型作为参数传递,使代码更通用。例如List表示该列表只能存储String类型元素,避免了类型转换错误,提高了代码的可读性和可维护性。

43. Java中的ComparableComparator有何区别?

答案

特性ComparableComparator
定义位置类内部(implements Comparable类外部(单独实现Comparator接口)
方法int compareTo(T o)int compare(T o1, T o2)
排序逻辑类自身的默认排序(自然排序)外部定义的定制排序
适用场景固定排序逻辑灵活切换排序逻辑(如升序/降序)

代码示例

// Comparable:类内部实现
class Student implements Comparable<Student> {int age;@Overridepublic int compareTo(Student o) {return Integer.compare(this.age, o.age); // 按年龄升序}
}// Comparator:外部实现
class StudentNameComparator implements Comparator<Student> {@Overridepublic int compare(Student s1, Student s2) {return s1.name.compareTo(s2.name); // 按姓名排序}
}

44. 什么是Java中的注解?

  • 答案:注解是Java 5.0引入的新特性,用于为代码添加元数据。它可以用于类、方法、变量等上面,提供信息给编译器、开发工具或运行时环境。例如@Override注解用于标识方法重写,@Deprecated注解表示方法已过时等。

45. Java中的线程池有什么作用?

  • 答案:线程池用于管理和复用线程,避免频繁创建和销毁线程带来的开销,提高系统性能和资源利用率。常见的线程池类有ThreadPoolExecutor,可通过它创建不同类型的线程池,如FixedThreadPool(固定大小线程池)、CachedThreadPool(缓存线程池)等。

46. 解释Java中的双亲委派模型

原理:类加载器的委派机制,当加载类时,先委托父加载器加载,父加载器无法加载时才自己加载,避免类重复加载和安全问题(如自定义java.lang.String不会被加载)。
类加载器层次

  • 启动类加载器(Bootstrap ClassLoader):加载JAVA_HOME/lib下的类;
  • 扩展类加载器(Extension ClassLoader):加载JAVA_HOME/lib/ext下的类;
  • 应用类加载器(Application ClassLoader):加载类路径下的类;
  • 自定义类加载器:继承ClassLoader,重写findClass()

代码示例(类加载委派):

public class ClassLoaderDemo {public static void main(String[] args) {// 获取当前类的类加载器(应用类加载器)ClassLoader appClassLoader = ClassLoaderDemo.class.getClassLoader();System.out.println(appClassLoader); // 输出sun.misc.Launcher$AppClassLoader// 父加载器(扩展类加载器)ClassLoader extClassLoader = appClassLoader.getParent();System.out.println(extClassLoader); // 输出sun.misc.Launcher$ExtClassLoader// 启动类加载器(C++实现,返回null)ClassLoader bootstrapClassLoader = extClassLoader.getParent();System.out.println(bootstrapClassLoader); // 输出null}
}

47. Java中的字符编码有哪些常见类型,它们有什么区别?

  • 答案:常见的字符编码有ASCII、UTF - 8、UTF - 16等。ASCII编码用7位二进制数表示一个字符,只能表示英文字母、数字和一些特殊字符;UTF - 8是一种可变长度编码,可表示世界上几乎所有字符,对英文字符用1个字节表示,对其他字符根据需要用2 - 4个字节表示;UTF - 16通常用2个字节表示一个字符,但对于一些特殊字符需用4个字节。

48. 什么是Java中的函数式接口?如何使用Lambda表达式?

  • 原理:函数式接口是只包含一个抽象方法的接口(可以有默认方法和静态方法),用@FunctionalInterface注解标识。Lambda表达式是函数式接口的实例化方式,用于简化匿名内部类的写法。
  • 代码示例
import java.util.function.Predicate;// 自定义函数式接口
@FunctionalInterface
interface Calculator {int calculate(int a, int b);
}public class FunctionalInterfaceDemo {public static void main(String[] args) {// 使用Lambda表达式实现Calculator接口Calculator add = (a, b) -> a + b;System.out.println(add.calculate(2, 3)); // 输出5// 内置函数式接口Predicate(判断条件)Predicate<Integer> isEven = num -> num % 2 == 0;System.out.println(isEven.test(4)); // 输出trueSystem.out.println(isEven.test(5)); // 输出false}
}

49. 简述Java中的泛型擦除机制

  • 原理:Java泛型是“伪泛型”,在编译阶段会进行类型擦除:编译器将泛型类型参数替换为其边界类型(若无边界则替换为Object),并在必要时插入类型转换代码。这意味着泛型信息在运行时不存在,无法通过反射获取泛型参数的具体类型(除非通过匿名内部类等特殊方式)。
  • 代码示例
import java.util.ArrayList;public class GenericErasureDemo {public static void main(String[] args) {ArrayList<String> strList = new ArrayList<>();ArrayList<Integer> intList = new ArrayList<>();// 类型擦除后,两者的运行时类型相同System.out.println(strList.getClass() == intList.getClass()); // 输出true// 编译时泛型检查,运行时无限制(可通过反射绕过)try {strList.getClass().getMethod("add", Object.class).invoke(strList, 10);System.out.println(strList); // 输出[10],说明运行时无泛型限制} catch (Exception e) {e.printStackTrace();}}
}

50. 什么是Java中的线程局部变量(ThreadLocal)?如何使用?

  • 原理ThreadLocal用于为每个线程提供独立的变量副本,确保线程间数据隔离。其内部通过Thread类中的threadLocals(类型为ThreadLocalMap)存储数据,每个ThreadLocal对象作为key,对应的线程私有值作为value。
  • 注意:使用后需手动调用remove()方法清理数据,否则可能导致内存泄漏(ThreadLocalMap中的Entry是弱引用key,但value是强引用,若线程长期存活,value无法回收)。
  • 代码示例
public class ThreadLocalDemo {// 定义ThreadLocal变量,指定泛型类型为Stringprivate static ThreadLocal<String> threadLocal = new ThreadLocal<>();public static void main(String[] args) {// 线程1设置并获取值new Thread(() -> {threadLocal.set("线程1的数据");System.out.println(Thread.currentThread().getName() + ":" + threadLocal.get());threadLocal.remove(); // 清理数据}, "线程1").start();// 线程2设置并获取值new Thread(() -> {threadLocal.set("线程2的数据");System.out.println(Thread.currentThread().getName() + ":" + threadLocal.get());threadLocal.remove(); // 清理数据}, "线程2").start();}
}
// 输出:
// 线程1:线程1的数据
// 线程2:线程2的数据
No.大剑师精品GIS教程推荐
0地图渲染基础- 【WebGL 教程】 - 【Canvas 教程】 - 【SVG 教程】
1Openlayers 【入门教程】 - 【源代码+示例 300+】
2Leaflet 【入门教程】 - 【源代码+图文示例 150+】
3MapboxGL【入门教程】 - 【源代码+图文示例150+】
4Cesium 【入门教程】 - 【源代码+综合教程 200+】
5threejs【中文API】 - 【源代码+图文示例200+】

51. 解释Java中的动态代理及其实现方式

原理:动态代理允许在运行时创建目标类的代理对象,增强目标方法(如日志、事务)而不修改源码。
实现方式

  • JDK动态代理:基于接口,通过Proxy.newProxyInstance()生成代理类;
  • CGLIB动态代理:基于继承,通过生成目标类子类实现代理(需引入CGLIB库)。

代码示例(JDK动态代理):

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;// 目标接口
interface Target {void doSomething();
}// 目标实现类
class TargetImpl implements Target {@Overridepublic void doSomething() {System.out.println("执行目标方法");}
}// 代理处理器
class ProxyHandler implements InvocationHandler {private Object target;public ProxyHandler(Object target) {this.target = target;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("代理:方法执行前"); // 增强逻辑Object result = method.invoke(target, args); // 调用目标方法System.out.println("代理:方法执行后");return result;}
}public class DynamicProxyDemo {public static void main(String[] args) {Target target = new TargetImpl();// 生成代理对象(基于接口)Target proxy = (Target) Proxy.newProxyInstance(Target.class.getClassLoader(),new Class[]{Target.class},new ProxyHandler(target));proxy.doSomething();}
}
// 输出:代理:方法执行前 → 执行目标方法 → 代理:方法执行后

52. 什么是Java中的注解(Annotation)?如何自定义注解?

原理:注解是代码的元数据,用于标记类、方法等,可通过反射解析。内置注解如@Override@Deprecated,自定义注解需用@interface声明。
核心元注解

  • @Retention:指定注解保留阶段(源码、字节码、运行时);
  • @Target:指定注解可修饰的元素(类、方法等)。

代码示例

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;// 自定义注解
@Retention(RetentionPolicy.RUNTIME) // 运行时保留,可通过反射获取
@Target(ElementType.METHOD) // 仅修饰方法
@interface Log {String value() default "执行方法"; // 注解属性
}public class AnnotationDemo {@Log("测试方法") // 使用注解public void test() {System.out.println("测试方法执行");}public static void main(String[] args) throws Exception {// 反射获取注解Log log = AnnotationDemo.class.getMethod("test").getAnnotation(Log.class);System.out.println(log.value()); // 输出:测试方法}
}

53. 解释Java中的序列化与反序列化

原理:序列化将对象转换为字节流(便于存储/传输),反序列化则将字节流恢复为对象。需实现Serializable接口(标记接口,无方法),transient关键字修饰的字段不参与序列化。

代码示例

import java.io.*;class User implements Serializable { // 实现Serializable接口private String name;private transient int age; // transient字段不序列化public User(String name, int age) {this.name = name;this.age = age;}@Overridepublic String toString() {return "User{name='" + name + "', age=" + age + "}";}
}public class SerializationDemo {public static void main(String[] args) throws IOException, ClassNotFoundException {// 序列化User user = new User("Alice", 20);ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("user.ser"));oos.writeObject(user);oos.close();// 反序列化ObjectInputStream ois = new ObjectInputStream(new FileInputStream("user.ser"));User deserializedUser = (User) ois.readObject();ois.close();System.out.println(deserializedUser); // 输出:User{name='Alice', age=0}(age被transient修饰,未序列化)}
}

54. Java中的equals()==有什么区别?

原理

  • ==:比较基本类型时为值比较;比较引用类型时为内存地址(对象是否为同一实例)比较。
  • equals():Object类默认实现为==,但可重写(如String类重写为值比较)。

代码示例

public class EqualsDemo {public static void main(String[] args) {// 基本类型比较int a = 10;int b = 10;System.out.println(a == b); // true(值相等)// 引用类型比较String s1 = new String("hello");String s2 = new String("hello");System.out.println(s1 == s2); // false(地址不同)System.out.println(s1.equals(s2)); // true(String重写equals,比较值)}
}

55. 什么是Java中的Lambda表达式?适用于什么场景?

原理:Lambda是函数式接口的匿名实现,简化代码。格式:(参数) -> 表达式/代码块
适用场景:简化集合遍历(如forEach)、线程创建、Stream API等。

代码示例

import java.util.Arrays;
import java.util.List;public class LambdaDemo {public static void main(String[] args) {// 1. 简化线程创建(Runnable是函数式接口)new Thread(() -> System.out.println("Lambda线程运行")).start();// 2. 集合遍历List<String> list = Arrays.asList("a", "b", "c");list.forEach(str -> System.out.println(str)); // 输出a、b、c// 3. 简化Comparatorlist.sort((s1, s2) -> s2.compareTo(s1)); // 倒序排序System.out.println(list); // 输出[c, b, a]}
}

56. 解释Java中的Stream API及其常用操作

原理:Stream API用于处理集合数据,支持链式操作(过滤、映射、聚合等),类似SQL查询,分为中间操作(返回Stream)和终端操作(返回结果)。

常用操作

  • filter():过滤元素;
  • map():转换元素;
  • collect():收集结果(如转List);
  • count():统计元素数。

代码示例

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;public class StreamDemo {public static void main(String[] args) {List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);// 过滤偶数 → 乘以2 → 收集为ListList<Integer> result = numbers.stream().filter(n -> n % 2 == 0) // 中间操作:保留偶数.map(n -> n * 2) // 中间操作:乘以2.collect(Collectors.toList()); // 终端操作:转ListSystem.out.println(result); // 输出[4, 8, 12]}
}

57. Java中的volatile关键字有什么作用?

原理volatile保证变量的可见性和禁止指令重排序,但不保证原子性。

  • 可见性:线程修改volatile变量后,立即刷新到主内存,其他线程读取时从主内存加载;
  • 有序性:禁止编译器和CPU对volatile变量相关指令重排序(如单例模式中的双重检查锁)。

代码示例(禁止重排序):

public class VolatileDemo {private static volatile VolatileDemo instance; // 禁止重排序private VolatileDemo() {}public static VolatileDemo getInstance() {if (instance == null) {synchronized (VolatileDemo.class) {if (instance == null) {// 若不加volatile,可能发生指令重排序:// 1. 分配内存 → 2. 实例化对象 → 3. 赋值给instance// 重排序后可能为1→3→2,导致其他线程获取到未初始化的instanceinstance = new VolatileDemo();}}}return instance;}
}

58. Java中的try-with-resources语法有什么作用?

原理try-with-resources用于自动关闭实现AutoCloseable接口的资源(如流、连接),替代传统的try-finally,避免资源泄漏。

代码示例

import java.io.FileInputStream;
import java.io.IOException;public class TryWithResources {public static void main(String[] args) {// 资源在try块结束后自动关闭try (FileInputStream fis = new FileInputStream("test.txt")) {int data = fis.read();while (data != -1) {System.out.print((char) data);data = fis.read();}} catch (IOException e) { // 统一处理异常e.printStackTrace();}// 无需手动调用fis.close()}
}

59. 解释Java中的深拷贝与浅拷贝

原理

  • 浅拷贝:复制对象时,仅复制基本类型字段,引用类型字段仍指向原对象(如Object.clone()默认实现);
  • 深拷贝:复制对象及引用类型字段指向的所有对象,完全独立于原对象(需手动实现,如序列化/反序列化或递归克隆)。

代码示例

import java.util.Arrays;class Person implements Cloneable {private String name;private int[] ages; // 引用类型public Person(String name, int[] ages) {this.name = name;this.ages = ages;}// 浅拷贝(默认clone)@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}// 深拷贝(手动复制引用类型)public Person deepClone() throws CloneNotSupportedException {Person clone = (Person) super.clone();clone.ages = Arrays.copyOf(this.ages, this.ages.length); // 复制数组return clone;}// getter/setter省略
}public class CopyDemo {public static void main(String[] args) throws CloneNotSupportedException {int[] ages = {20, 30};Person original = new Person("Alice", ages);// 浅拷贝Person shallowClone = (Person) original.clone();shallowClone.ages[0] = 25;System.out.println(original.ages[0]); // 输出25(原对象被修改)// 深拷贝Person deepClone = original.deepClone();deepClone.ages[0] = 30;System.out.println(original.ages[0]); // 输出25(原对象未被修改)}
}

60. Java中的StringStringBuilderStringBuffer有什么区别?

原理

  • String:不可变字符序列(底层char[]final修饰),每次修改创建新对象,效率低;
  • StringBuilder:可变字符序列,非线程安全,效率高(单线程推荐);
  • StringBuffer:可变字符序列,线程安全(方法加synchronized),效率低(多线程推荐)。

代码示例

public class StringCompare {public static void main(String[] args) {String str = "a";str += "b"; // 创建新String对象(原对象不变)StringBuilder sb = new StringBuilder("a");sb.append("b"); // 直接修改内部数组,无新对象StringBuffer sbf = new StringBuffer("a");sbf.append("b"); // 线程安全的append}
}

二、120道面试题目录列表

文章序号Java面试题120道
1Java面试题及详细答案120道(01-20)
2Java面试题及详细答案120道(21-40)
3Java面试题及详细答案120道(41-60)
4Java面试题及详细答案120道(61-80)
5Java面试题及详细答案120道(81-100)
6Java面试题及详细答案120道(5101-120)
http://www.xdnf.cn/news/16282.html

相关文章:

  • 排序算法,咕咕咕
  • 进制定义与转换详解
  • vcpkg如何交叉编译
  • HCLP--MGER综合实验
  • 数据结构习题--删除排序数组中的重复项
  • 详解力扣高频SQL50题之1084. 销售分析 III【简单】
  • Python点阵字生成与优化:从基础实现到高级渲染技术
  • 数据恢复与备份
  • 快速入门Linux操作系统(一)
  • 立式加工中心X-Y轴传动机械结构设“cad【6张】三维图+设计说明书
  • 进阶数据结构:用红黑树实现封装map和set
  • 学习嵌入式的第三十一天-数据结构-(2025.7.23)网络协议封装
  • 数据中心-时序数据库InfluxDB
  • 掌握Gemini-2.5:现代AI开发中实用应用的综合指南
  • 二次函数图像动画展示
  • 在Power Automate Desktop中执行PowerShell获取SharePoint online某个文件夹的用户权限列表
  • excel删除重复项场景
  • 算法竞赛阶段二-数据结构(35)数据结构单链表模拟实现
  • Node.js 模拟 Linux 环境
  • 【每天一个知识点】GAN(生成对抗网络,Generative Adversarial Network)
  • Whisper语音转文字
  • 【洛谷】单向链表、队列安排、约瑟夫问题(list相关算法题)
  • 互联网应用主流框架整合 Spring Boot开发
  • Linux DNS 服务器正反向解析
  • 【IMMCKF】基于容积卡尔曼滤波(CKF)的多模型交互的定位程序,模型为CV和CT,三维环境,matlab代码|附下载链接
  • Nestjs框架: 基于Mongodb的多租户功能集成和优化
  • 算子推理是什么
  • 电脑开机后网络连接慢?
  • (Python)文件储存的认识,文件路径(文件储存基础教程)(Windows系统文件路径)(基础教程)
  • 【17】C# 窗体应用WinForm ——【文本框TextBox、富文本框RichTextBox 】属性、方法、实例应用