以下是Java设计模式面试中高频且核心的题目,涵盖基础概念、常用模式及应用场景,帮助快速掌握考点:
一、基础概念题
1. 什么是Java设计模式?它的核心作用是什么?
Java设计模式是一套反复验证、用于解决特定场景下代码设计问题的“最佳实践”,核心作用是提高代码的可复用性、可维护性和可扩展性,降低模块间耦合。
2. 设计模式的六大原则(SOLID原则)分别是什么?
- 单一职责原则(SRP):一个类只负责一个功能领域的职责。
- 开放-关闭原则(OCP):对扩展开放,对修改关闭。
- 里氏替换原则(LSP):子类可替换父类,且不改变原有程序逻辑。
- 依赖倒置原则(DIP):依赖抽象,不依赖具体实现(面向接口编程)。
- 接口隔离原则(ISP):用多个专用接口替代一个通用接口,避免接口臃肿。
- 迪米特法则(LOD):一个对象应尽可能少地了解其他对象(“最少知道原则”)。
3. 设计模式分为哪三大类?每类包含哪些常见模式? - 创建型模式:负责对象创建,解耦“对象创建”与“使用”,如单例、工厂方法、抽象工厂、建造者、原型。
- 结构型模式:处理类/对象的组合关系,优化结构,如代理、适配器、装饰器、桥接、组合、外观、享元。
- 行为型模式:描述类/对象的交互逻辑(通信、职责分配),如策略、模板方法、观察者、迭代器、责任链、命令、备忘录、状态、访问者、中介者、解释器。
二、高频重点模式题
- 单例模式
- 问题1:单例模式的核心目标是什么?有哪些实现方式?
目标:确保一个类仅存在一个实例,并提供全局唯一的访问入口。
常见实现:饿汉式、懒汉式(线程不安全/安全)、双重检查锁(DCL)、静态内部类、枚举。 - 问题2:双重检查锁(DCL)实现单例时,为什么要给实例变量加 volatile ?
不加 volatile 可能出现“指令重排”: new Singleton() 会拆分为“分配内存→初始化对象→赋值给变量”,若重排为“分配内存→赋值→初始化”,线程B可能拿到“未初始化的实例”,导致空指针。 volatile 可禁止指令重排,保证实例初始化完成后才被访问。 - 问题3:枚举单例的优势是什么?
天然避免线程安全问题,且能防止反射破坏单例(反射无法创建枚举实例)、防止序列化/反序列化破坏单例(枚举默认实现 readResolve() ,返回原实例)。
- 工厂模式(工厂方法/抽象工厂)
- 问题1:简单工厂、工厂方法、抽象工厂的区别是什么?
- 简单工厂:1个工厂类创建所有产品(违反OCP,新增产品需修改工厂)。
- 工厂方法:1个产品对应1个工厂子类(符合OCP,新增产品只需加“产品类+工厂子类”),解决“单一产品族”创建。
- 抽象工厂:1个工厂创建“多个相关联的产品”(产品族),解决“多产品族”创建(新增产品族需加工厂,新增产品需修改所有工厂,违反OCP)。
- 问题2:抽象工厂模式的应用场景?举例说明。
场景:需要创建“一组相互依赖的产品”时,如“电脑配件”(产品族:Intel系列、AMD系列;产品:CPU、主板),Intel工厂创建Intel CPU+Intel主板,AMD工厂创建AMD CPU+AMD主板。
- 代理模式
- 问题1:代理模式的核心作用是什么?分为哪几类?
作用:为目标对象提供“代理对象”,控制对目标对象的访问(如增强功能、权限控制、日志记录)。
分类:静态代理(编译期生成代理类)、动态代理(运行期生成代理类,如JDK动态代理、CGLIB动态代理)。 - 问题2:JDK动态代理和CGLIB动态代理的区别?
- JDK动态代理:基于接口,代理类需实现目标对象的接口,底层用 Proxy 类和 InvocationHandler 生成代理实例。
- CGLIB动态代理:基于继承,代理类继承目标对象(目标类不能是final),底层用ASM字节码框架生成子类。
- 装饰器模式
- 问题1:装饰器模式和继承的区别?为什么说装饰器更灵活?
- 继承:静态扩展,子类一旦定义就固定了功能,且多层继承会导致类爆炸。
- 装饰器:动态扩展,通过“包装目标对象”添加功能,可灵活组合多个装饰器(如给“咖啡”依次加“牛奶”“糖”),符合OCP。
- 问题2:Java中哪些类用到了装饰器模式?
IO流:如 BufferedReader (装饰 Reader ,加缓冲功能)、 DataInputStream (装饰 InputStream ,加数据类型读取功能), InputStream/Reader 是抽象组件,具体组件如 FileInputStream ,装饰器如 BufferedInputStream 。
- 观察者模式
- 问题1:观察者模式的核心角色?应用场景?
核心角色:主题(被观察者,维护观察者列表,通知更新)、观察者(接收主题通知,执行更新逻辑)。
场景:对象间存在“一对多”依赖,一个对象变化需通知多个对象,如GUI事件监听(按钮点击通知多个监听器)、消息订阅(公众号推送通知订阅者)。 - 问题2:Java中的 Observable 类和 Observer 接口有什么缺点?
- Observable 是类而非接口,限制了复用(子类需继承它,无法继承其他类)。
- 通知方式单一(仅 notifyObservers() ,无法指定通知顺序或过滤观察者)。
- 线程不安全(未加锁,多线程下修改观察者列表可能出问题)。
三、场景应用题
1. “Spring中的Bean默认是单例,它是如何保证线程安全的?”
Spring本身不保证Bean的线程安全,因单例Bean是“无状态”的(不含可修改的成员变量):
- 若Bean无状态(如 Service 、 Dao ),多线程共享时无安全问题;
- 若Bean有状态(如含 User 成员变量),需手动保证线程安全(如用 ThreadLocal 、加锁)。
2. “MyBatis中的 SqlSession 是单例还是多例?为什么?”
多例。因 SqlSession 是有状态的(关联了连接 Connection 和事务),若为单例,多线程共享时会导致连接混乱、事务交叉,因此每次请求需创建新的 SqlSession (由 SqlSessionFactory 创建)。
3. “如何用设计模式解决‘支付方式多样化’的问题(如微信支付、支付宝支付、银联支付)?”
用策略模式: - 定义抽象策略接口 PaymentStrategy (含 pay() 方法);
- 具体策略类 WechatPayment 、 AlipayPayment 、 UnionPayPayment ,实现 pay() ;
- 上下文类 PaymentContext ,持有 PaymentStrategy 引用,调用 pay() ;
- 新增支付方式时,只需加具体策略类,无需修改原有代码,符合OCP。
1431

被折叠的 条评论
为什么被折叠?



