每日 Java 面试题分享【第 16 天】

embedded/2025/2/3 18:47:19/

欢迎来到每日 Java 面试题分享栏目!
订阅专栏,不错过每一天的练习

今日分享 3 道面试题目!

评论区复述一遍印象更深刻噢~

目录

  • 问题一:Java 运行时异常和编译时异常之间的区别是什么?
  • 问题二:什么是 Java 中的继承机制?
  • 问题三:什么是 Java 的封装特性?

问题:Java 运行时异常和编译时异常之间的区别是什么?


面试官考察点

  1. 异常分类理解:对 Java 异常体系(Throwable、Error、Exception、RuntimeException)的掌握程度。
  2. 处理机制:是否清楚两种异常在代码中的处理方式差异(强制处理 vs 非强制)。
  3. 设计意图:能否理解 Java 对这两类异常的设计哲学(可控性问题 vs 程序逻辑错误)。
  4. 实战经验:是否能在项目中正确选择异常类型,避免滥用。

参考答案

1. 定义与继承关系
  • 编译时异常(Checked Exception)
    • 继承自 Exception,但不是RuntimeException 的子类。
    • 例如:IOExceptionSQLExceptionClassNotFoundException
    • 必须在代码中显式处理(try-catch 捕获或 throws 声明),否则编译失败。
  • 运行时异常(Unchecked Exception)
    • 继承自 RuntimeExceptionRuntimeException 本身继承 Exception)。
    • 例如:NullPointerExceptionArrayIndexOutOfBoundsExceptionIllegalArgumentException
    • 不需要强制处理,代码中可以不捕获或声明。

2. 核心区别
维度编译时异常运行时异常
处理要求必须显式处理,否则编译失败可不处理,由 JVM 抛出并终止线程
设计目的表示程序外部可控问题(如文件不存在、网络中断)表示程序内部逻辑错误(如空指针、数组越界)
代码可读性通过 throws 声明明确调用方需处理的异常类型通常通过代码逻辑规避,而非显式处理

3. 底层机制
  • 编译时异常
    • 编译器通过语法检查强制约束,确保程序员对可能发生的 " 已知风险 " 进行处理。
    • 例如,读取文件时必须处理 IOException,防止程序因外部资源问题崩溃。
  • 运行时异常
    • 通常由程序逻辑错误引发,属于 " 程序员应避免的错误 ",如未做空判断直接调用方法。
    • JVM 在运行时会自动抛出,若不捕获则线程终止(可通过全局异常处理器兜底,如 Spring 的 @ControllerAdvice)。

4. 项目实战结合

场景:在电商项目的订单支付模块中,调用第三方支付接口时可能发生网络超时(编译时异常),而参数校验不通过(如金额为负数)属于运行时异常。
处理方式

  1. 编译时异常
    java">try {  PaymentResponse response = paymentClient.call(externalApi);  
    } catch (IOException e) {  // 记录日志并触发重试机制  log.error("支付接口调用失败", e);  retryPolicy.retry();  
    }  
    
  2. 运行时异常
    java">// 参数校验(通过Preconditions或Assert)  
    public void createOrder(BigDecimal amount) {  Preconditions.checkArgument(amount.compareTo(BigDecimal.ZERO) > 0, "金额必须大于0");  // 业务逻辑  
    }  
    

总结

  • 编译时异常用于外部依赖的容错处理(如 IO、数据库连接)。
  • 运行时异常用于快速暴露代码逻辑缺陷,避免无效状态扩散。

5. 高频追问预判

  1. 为什么 Java 要设计两种异常?

    • :编译时异常强制处理 " 已知但不可控 " 的问题(如文件丢失),运行时异常用于标识 " 本应通过代码避免 " 的逻辑错误,减少冗余的 try-catch 代码。
  2. 如何自定义异常?应该继承哪一类?

    • :业务异常通常继承 RuntimeException(如 BusinessException),避免调用方强制处理;若异常需调用方显式关注(如特定 API 的错误码),可继承 Exception
  3. 实际项目中常见的异常处理误区?

      • 捕获 Exception 但不处理(如 e.printStackTrace()),导致问题被掩盖。
      • 滥用 RuntimeException 传递业务错误,应通过返回错误码或自定义状态对象。

通过分层拆解异常的设计哲学、处理机制和实战场景,可以体现对 Java 异常体系的深入理解,这正是大厂面试官期待的答案!



问题:什么是 Java 中的继承机制?


面试官考察点

  1. 面向对象基础:是否理解继承在面向对象编程中的核心地位。
  2. 实现细节:对继承的语法、方法重写(Override)、访问控制等机制的掌握。
  3. 设计思想:能否区分继承与组合的适用场景,避免滥用继承。
  4. 底层原理:对 JVM 中继承实现机制(如方法表、内存结构)的理解。

参考答案

1. 核心定义与语法
  • 定义:继承是面向对象编程中类与类之间的一种关系,允许子类(派生类)复用父类(基类)的属性和方法,并可以通过重写(Override)或扩展实现新功能。

  • 语法

    java">class Parent {  public void print() {  System.out.println("Parent Method");  }  
    }  
    class Child extends Parent {  @Override  public void print() {  super.print(); // 调用父类方法  System.out.println("Child Method");  }  
    }  
    
  • 关键字extends(单继承)、super(访问父类成员)、@Override(注解声明方法重写)。


2. 核心机制与规则
  • 单继承限制:Java 不支持多继承(一个类只能直接继承一个父类),但可通过接口(implements)实现多继承效果。
  • 访问权限控制
    • 子类可访问父类的 publicprotected 成员,但无法直接访问 private 成员(需通过父类提供的公共方法)。
    • 父类的构造方法不继承,但子类构造器必须显式或隐式调用父类构造器(super())。
  • 方法重写规则(Override):
    • 签名一致:方法名、参数列表、返回类型(Java 5+ 允许协变返回类型)必须相同。
    • 访问权限:子类方法的访问权限不能比父类更严格(例如父类 protected,子类不能改为 private)。
    • 异常声明:子类方法抛出的异常不能比父类更宽泛(可抛出更具体异常或不抛出)。

3. 底层实现原理
  • 内存结构:子类对象在堆中会包含父类的实例变量(即使为 private,但无法直接访问)。
  • 方法调用
    • JVM 通过虚方法表(vtable) 实现动态绑定(多态)。
    • 每个类的方法表存储其所有可继承方法的入口地址,子类重写的方法会覆盖父类方法在表中的引用。
  • 类加载机制
    • 加载子类时,JVM 会先递归加载其父类(直至 Object 类)。
    • 父类的静态代码块优先于子类执行。

4. 项目实战结合

场景:在电商系统的订单模块中,抽象出 BaseOrder 类,包含订单创建时间、订单状态等公共字段和方法,NormalOrder(普通订单)和 GroupBuyOrder(团购订单)继承并扩展特定逻辑。

java">public abstract class BaseOrder {  protected LocalDateTime createTime;  protected OrderStatus status;  public void validate() {  if (createTime == null) {  throw new IllegalArgumentException("创建时间不能为空");  }  }  
}  public class GroupBuyOrder extends BaseOrder {  private int groupId;  @Override  public void validate() {  super.validate(); // 复用父类校验  if (groupId <= 0) {  throw new IllegalArgumentException("团购ID无效");  }  }  
}  

设计要点

  • 通过继承实现代码复用,避免重复校验逻辑。
  • 使用抽象类定义通用行为,子类通过重写扩展差异化逻辑。

5. 继承 vs 组合
维度继承(is-a)组合(has-a)
关系强耦合,子类依赖父类实现松耦合,通过持有其他类的对象实现功能复用
灵活性父类修改可能破坏子类可动态替换组合对象(如策略模式)
适用场景明确 " 是一种 " 关系(如 Dog extends Animal功能复用但无需继承全部能力(如 Car has Engine

最佳实践:优先使用组合,仅在逻辑上严格符合 “is-a” 关系时使用继承(遵循里氏替换原则)。


6. 高频追问预判

  1. 为什么 Java 不支持多继承?

    • :避免 " 菱形继承问题 "(多个父类有同名方法时冲突)。Java 通过接口(支持多实现)和内部类间接解决。
  2. 子类实例化时父类的构造方法如何调用?

    • :子类构造器默认隐式调用父类无参构造器(super()),若父类没有无参构造器,子类必须显式调用 super(args)
  3. 重写(Override)和重载(Overload)的区别?

      • 重写:子类重新定义父类方法,方法签名相同,实现多态。
      • 重载:同一类中方法名相同但参数列表不同,实现方法多样化调用。

通过结合语法、底层原理、设计原则和实战案例,可以全面展示对继承机制的掌握,这正是大厂面试中区分候选人的关键点!


问题:什么是 Java 的封装特性?


面试官考察点

  1. 面向对象基础:是否理解封装在面向对象编程中的核心意义。
  2. 实现手段:对访问控制修饰符(private/protected/public)和方法的合理使用。
  3. 设计思想:能否结合高内聚、低耦合原则,说明封装如何提升代码健壮性。
  4. 实战经验:是否在项目中正确应用封装解决实际问题(如数据校验、逻辑隔离)。

参考答案

1. 核心定义与目的
  • 定义:封装(Encapsulation)是面向对象编程的三大特性之一,指将数据(属性)和行为(方法)绑定为一个类,并对外隐藏内部实现细节,仅通过受控的接口暴露必要功能。
  • 目的
    • 安全性:防止外部直接修改对象内部状态(如字段非法赋值)。
    • 灵活性:内部实现可独立修改,不影响外部调用方。
    • 易用性:通过明确的接口简化复杂逻辑的使用(如 ArrayList 隐藏动态扩容细节)。

2. 核心机制与实现
  • 访问控制修饰符

    修饰符类内包内子类任意位置
    private
    protected
    public
  • 典型实现方式

    java">public class BankAccount {  // 私有字段:外部无法直接访问  private double balance;  // 公有方法:受控的访问入口  public void deposit(double amount) {  if (amount > 0) {  balance += amount;  } else {  throw new IllegalArgumentException("存款金额必须大于0");  }  }  public double getBalance() {  return balance;  }  
    }  
    
    • 隐藏实现:余额 balance 字段私有,防止外部直接修改。
    • 逻辑封装:存款操作通过 deposit() 方法实现校验和计算。

3. 底层原理与设计原则
  • 数据隐藏的本质
    • JVM 允许通过反射强制访问私有字段(setAccessible(true)),但封装是设计层面的约束,依赖于开发者遵守规范。
  • 与设计原则的关联
    • 迪米特法则(最少知识原则):只与直接朋友交互,避免暴露过多细节。
    • 开闭原则:通过封装内部实现,使得类可以扩展(新增功能)而无需修改已有接口。

4. 项目实战结合

场景:在电商系统的用户模块中,封装用户敏感信息(如密码),确保数据安全和一致性。

java">public class User {  private String username;  private String encryptedPassword; // 加密后的密码  public void setPassword(String plainPassword) {  if (plainPassword.length() < 8) {  throw new IllegalArgumentException("密码长度至少8位");  }  this.encryptedPassword = encrypt(plainPassword); // 加密逻辑封装在内部  }  public boolean validatePassword(String input) {  return encrypt(input).equals(encryptedPassword);  }  // 私有方法:隐藏加密算法细节  private String encrypt(String data) {  // 使用SHA-256等算法加密  }  
}  

设计优势

  • 密码存储与校验逻辑封装在 User 类内部,外部无法绕过规则直接修改。
  • 加密算法变更时(如从 MD5 升级为 SHA-256),只需修改 encrypt() 方法,不影响调用方。

5. 封装的多层次性
层级示例封装目标
类级别字段私有化 + 公共方法保护对象状态,隐藏实现细节
包级别使用包级私有(无修饰符)类或方法限制跨包访问,实现模块内高内聚
模块级Java 9 模块化(module-info.java控制模块间的依赖和暴露(如 Spring Boot)

6. 高频追问预判

  1. 封装与抽象的区别?

      • 封装:隐藏实现细节,控制访问(解决 " 怎么做 " 的暴露问题)。
      • 抽象:提取共性,定义接口或抽象类(解决 " 做什么 " 的规范问题)。
    • 示例List 接口抽象了 " 线性表 " 操作,ArrayList 封装了动态数组的实现细节。
  2. 什么时候该用 protected 修饰符?

    • :当需要允许子类访问父类成员,但禁止非子类的外部访问时(如模板方法模式中的钩子方法)。
  3. 如何避免过度封装?

      • 避免为每个字段机械添加 getter/setter,应根据业务需求设计接口。
      • 例如,订单的 totalPrice 可能不需要 setter,而是通过 calculateTotal() 方法内部计算。

通过结合语法规范、设计原则和实战案例,可以清晰展示对封装特性的深入理解,这正是大厂面试中区分候选人的关键!


总结

今天的 3 道 Java 面试题,您是否掌握了呢?持续关注我们的每日分享,深入学习 Java 面试的各个细节,快速提升技术能力!如果有任何疑问,欢迎在评论区留言,我们会第一时间解答!

明天见!🎉


http://www.ppmy.cn/embedded/159243.html

相关文章

2181、合并零之间的节点

2181、[中等] 合并零之间的节点 1、问题描述&#xff1a; 给你一个链表的头节点 head &#xff0c;该链表包含由 0 分隔开的一连串整数。链表的 开端 和 末尾 的节点都满足 Node.val 0 。 对于每两个相邻的 0 &#xff0c;请你将它们之间的所有节点合并成一个节点&#xff…

minimind - 从零开始训练小型语言模型

大语言模型&#xff08;LLM&#xff09;领域&#xff0c;如 GPT、LLaMA、GLM 等&#xff0c;虽然它们效果惊艳&#xff0c; 但动辄10 Bilion庞大的模型参数个人设备显存远不够训练&#xff0c;甚至推理困难。 几乎所有人都不会只满足于用Lora等方案fine-tuing大模型学会一些新的…

【开源免费】基于SpringBoot+Vue.JS体育馆管理系统(JAVA毕业设计)

本文项目编号 T 165 &#xff0c;文末自助获取源码 \color{red}{T165&#xff0c;文末自助获取源码} T165&#xff0c;文末自助获取源码 目录 一、系统介绍二、数据库设计三、配套教程3.1 启动教程3.2 讲解视频3.3 二次开发教程 四、功能截图五、文案资料5.1 选题背景5.2 国内…

LeetCode435周赛T2贪心

题目描述 给你一个由字符 N、S、E 和 W 组成的字符串 s&#xff0c;其中 s[i] 表示在无限网格中的移动操作&#xff1a; N&#xff1a;向北移动 1 个单位。S&#xff1a;向南移动 1 个单位。E&#xff1a;向东移动 1 个单位。W&#xff1a;向西移动 1 个单位。 初始时&#…

ubuntu 下使用deepseek

安装Ollama sudo snap install ollama 执行 ollama run deepseek-coder 然后进行等待。。。

【apt源】RK3588 平台ubuntu20.04更换apt源

RK3588芯片使用的是aarch64架构&#xff0c;因此在Ubuntu 20.04上更换apt源时需要使用针对aarch64架构的源地址。以下是针对RK3588芯片在Ubuntu 20.04上更换apt源到清华源的正确步骤&#xff1a; 步骤一&#xff1a;打开终端 在Ubuntu 20.04中&#xff0c;按下Ctrl Alt T打…

Python学习之旅:进阶阶段(五)数据结构-双端队列(collections.deque)

在 Python 的进阶学习过程中,数据结构的掌握至关重要。今天要介绍的双端队列(deque,即 double-ended queue),是一种非常实用的数据结构,Python 的collections模块中的deque类为我们提供了强大的双端队列操作功能。接下来,就一起深入了解双端队列吧。 一、什么是双端队列…

解决国内服务器 npm install 卡住的问题

在使用国内云服务器时&#xff0c;经常会遇到 npm install 命令执行卡住的情况。本文将分享一个典型案例以及常见的解决方案。 问题描述 在执行以下命令时&#xff1a; mkdir test-npm cd test-npm npm init -y npm install lodash --verbose安装过程会卡在这个状态&#xf…