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

每日Java面试系列(15):进阶篇(String不可变的原因、性能问题、String三剑客、自定义不可变设计、组合优于继承等相关问题)

今日一句:若你现在肯努力,最坏的结果也只是大器晚成。

系列介绍

"Java面试基础篇"系列!本系列旨在帮助Java开发者系统性地准备面试,每天精选至少5道经典面试题,涵盖Java基础、进阶、框架等各方面知识。坚持学习21天,助你面试通关!
基础面试题:
每日5题Java面试系列基础(1)
每日5题Java面试系列基础(2)
每日5题Java面试系列基础(3)
每日5题Java面试系列基础(4)
每日5题Java面试系列基础(5)
每日5题Java面试系列基础(6)
进阶面试题:
每日5题Java面试系列进阶(7)
每日5题Java面试系列进阶(8)
每日5题Java面试系列进阶(9)
每日5题Java面试系列进阶(10)
每日5题Java面试系列进阶(11)
每日5题Java面试系列进阶(12)
每日5题Java面试系列进阶(13)
每日5题Java面试系列进阶(14)


一、不可变类深度剖析

1. 典型不可变类及设计原因

类名设计目的不可变性的价值
Integer封装基本类型,支持对象操作线程安全(原子性)、缓存优化(-128~127)
BigDecimal精确金融计算防止计算中途篡改导致结果错误
LocalDateTime日期时间处理时间值天然应不可变,避免并发修改
Collections.unmodifiableList()创建只读集合防御性编程,防止外部修改集合内容

设计本质
通过 final class + private final字段 + setter + 返回副本而非引用 实现,如 BigDecimal.add()

public BigDecimal add(BigDecimal augend) {// 创建新对象而非修改自身return new BigDecimal(this.intVal + augend.intVal, this.scale);
}

2. String不可变性的性能问题与优化

  • 问题根源
    String s = "";
    for (int i = 0; i < 10000; i++) {s += i;  // 每次循环产生新String对象,旧对象等待GC
    }
    
    • 产生 10000个中间对象,内存与GC压力巨大
  • 优化方案
    1. StringBuilder(非线程安全)
      StringBuilder sb = new StringBuilder();
      for (int i = 0; i < 10000; i++) {sb.append(i);
      }
      String result = sb.toString(); // 仅最终生成一个String
      
    2. JDK9+ 紧凑字符串(Compact Strings)
      • 底层将 char[] 改为 byte[] + 编码标记,内存占用降低40%
    3. 字符串常量池复用:字面量相同则复用对象

3. StringBuilder vs StringBuffer vs String

特性StringStringBuilderStringBuffer
可变性❌ 不可变⭕ 可变⭕ 可变
线程安全⭐ 天然安全❌ 不安全⭐ synchronized 方法
性能❌ 频繁拼接性能差⭐⭐ 单线程首选⭐ 多线程安全但性能较低
内存占用高(对象数多)低(单对象操作)低(单对象操作)

4. 自定义不可变类设计规范

public final class ImmutablePoint {// 1. final类 + final字段private final int x;private final int y;private final List<String> labels; // 引用类型需特殊处理// 2. 构造器初始化所有状态public ImmutablePoint(int x, int y, List<String> labels) {this.x = x;this.y = y;// 3. 防御性复制:防止外部修改传入的集合this.labels = Collections.unmodifiableList(new ArrayList<>(labels));}// 4. 不提供setter,只提供getterpublic int getX() { return x; }public List<String> getLabels() {// 5. 返回不可变副本return Collections.unmodifiableList(labels);}
}

关键防御点:对引用类型字段做深度保护(深拷贝或返回只读视图)


二、组合优于继承实战解析

1. 重构案例:支付渠道系统

  • 继承方案痛点

    PaymentChannel

    AlipayChannel

    +validate()

    WechatChannel

    +validate()

    BankCardChannel

    +validate()

    • 新增渠道需继承基类,重写方法易遗漏
    • 渠道验证逻辑分散,无法复用通用规则
  • 组合重构方案
    public interface Validator {boolean validate(PaymentRequest request);
    }public class PaymentChannel {private final Validator validator; // 组合验证策略private final String channelName;public PaymentChannel(Validator validator, String name) {this.validator = validator;this.channelName = name;}public boolean process(PaymentRequest request) {if (validator.validate(request)) {// 执行支付return true;}return false;}
    }// 使用示例:组合不同验证策略
    Validator strictValidator = new StrictValidator();
    PaymentChannel alipay = new PaymentChannel(strictValidator, "Alipay");
    

2. 组合 vs 聚合关键区别

关系组合(Composition)聚合(Aggregation)
生命周期整体控制部分的生命周期(同生共死)整体与部分独立存在
强度⭐⭐⭐ 强关系⭐⭐ 中关系
代码表现部分在整体构造函数中创建部分通过参数传入整体
UML实心菱形箭头空心菱形箭头
案例Car 拥有 Engine(车毁引擎亡)Department 包含 Employee(部门解散员工仍在)

3. 接口+组合实现灵活设计

设计模板

public class OrderService {private final PaymentProcessor processor; // 接口组合private final LoggingService logger;      // 接口组合public OrderService(PaymentProcessor processor, LoggingService logger) {this.processor = processor;this.logger = logger;}public void placeOrder(Order order) {processor.charge(order.getAmount());logger.log("Order placed: " + order.getId());}
}// 可插拔实现
interface PaymentProcessor { void charge(BigDecimal amount); }
interface LoggingService { void log(String message); }// 使用时注入不同实现
OrderService service = new OrderService(new AlipayProcessor(), new CloudLogger());

4. 体现"组合优于继承"的设计模式

模式组合体现解决继承痛点
策略模式将算法封装为独立策略对象注入Context避免算法实现污染主体类
装饰器模式通过嵌套装饰器对象动态扩展功能替代多层继承导致的类爆炸
桥接模式抽象部分与实现部分通过组合连接防止多维变化产生类数量乘积增长
代理模式代理对象组合真实对象,控制访问行为无需继承即可增强功能

回答技巧点睛

  1. 源码佐证:展示 Integer.valueOf() 的缓存机制源码片段
  2. 性能数据:对比 String 拼接与 StringBuilder 在10万次操作的耗时(如 5000ms vs 5ms)
  3. 反例警示:指出 java.util.Properties 继承 Hashtable 导致可插入非String键值的设计缺陷
  4. 架构演进:描述从继承重构为组合后,支付渠道系统扩展效率提升(新渠道开发从1天→1小时)
  5. 设计原则:引用《Effective Java》第18条:“组合优先于继承”
http://www.dtcms.com/a/336733.html

相关文章:

  • 数据结构——线性表
  • 蓝桥杯C++
  • 下降路径最小和
  • 《Java高并发核心编程》笔记汇总
  • 【Java企业级开发】(八)Spring框架中Web项目构建
  • 【高等数学】第九章 多元函数微分法及其应用——第六节 多元函数微分学的几何应用
  • Transformer架构的数学本质:从注意力机制到大模型时代的技术内核
  • AI 编程在老项目中的困境与改进方向
  • 负载测试与压力测试详解
  • MySQL黑盒子研究工具 strace
  • 基于因果性的深层语义知识图谱对文本预处理的积极影响
  • Perf使用详解
  • AI系统性思维复盘概述
  • 【FreeRTOS】事件组
  • 电力设备状态监测与健康管理:从数据感知到智能决策的技术实践​
  • 通达信【牛股妖股埋伏】副图+选股指标
  • 报错注入原理与全方法总结
  • HAL-ADC配置
  • 快速了解均值滤波处理
  • 关于动态代理的个人记录
  • CF2121B Above the Clouds
  • 【Java】多线程Thread类
  • 什么是AIGC(人工智能生成内容)
  • 牛客周赛 Round 104(小红的树不动点)
  • 人工智能入门②:AI基础知识(下)
  • 计算机程序编程软件开发设计之node..js语言开发的基于Vue框架的选课管理系统的设计与实现、基于express框架的在线选课系统的设计与实现
  • STM32——软硬件I2C
  • Font Awesome Kit 使用详解
  • OTA升级
  • Vue Router 嵌套路由与布局系统详解:从新手到精通