Java面向对象三大特性是封装、继承、多态,封装强调隐藏实现细节并暴露稳定契约,继承体现is-a关系且需谨慎使用以避免紧耦合,多态通过重写实现运行时动态绑定,三者共同支撑高内聚、低耦合、易扩展的工程设计。

大厂面试中 Java 面向对象(OOP)问题从来不是单点考察,而是层层递进的“连环炮”——从基础概念切入,迅速转向设计意图、边界场景、源码印证,最后落到真实业务取舍。破题关键不在背答案,而在建立“概念→动机→实现→权衡”的完整逻辑链。
封装:别只答“private + getter/setter”
面试官问“什么是封装”,如果只答访问控制,大概率被追问:“那 final 类、不可变对象、模块化(Java 9+ Module System)算不算封装?为什么?”
- 封装的本质是“隐藏实现细节 + 暴露稳定契约”,访问修饰符只是手段之一;
- 真正体现封装深度的地方在:异常是否暴露底层类型(比如把 SQLException 包装成自定义 ServiceException)、集合是否返回不可变视图(Collections.unmodifiableList)、Builder 模式如何避免构造非法对象;
- 反例:一个 Service 方法直接返回 ArrayList 并允许外部 add/remove,就破坏了封装边界。
继承 vs 组合:能说清“为什么 Spring 里几乎不用 extends”
这不是考教科书定义,而是看你是否理解框架设计哲学和演化代价。
- 继承表达“is-a”,但紧耦合、破坏封装、违反开闭原则(父类改,子类可能崩);
- Spring 的 Bean 生命周期、AOP、事务管理全靠组合(如 AbstractAutoProxyCreator 组合 Advisor、ProxyFactory),便于运行时动态替换、测试隔离、职责解耦;
- 实战建议:新项目优先用组合+接口+依赖注入;只有明确存在强层级语义且父类契约长期稳定时(如 java.util.AbstractList),才考虑继承。
多态的落地陷阱:重载(overload)和重写(override)别混淆
连环炮常从“重载和重写的区别”开始,但真正卡人的在后续:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
立即学习“Java免费学习笔记(深入)”;
- 重载是编译期决定,看引用类型;重写是运行期决定,看实际类型 —— 这点必须结合字节码(invokestatic vs invokevirtual)或 JMM 内存模型讲清楚;
- 面试官可能抛代码:父类方法 throws IOException,子类重写时能否 throw RuntimeException?能。但能否 throw SQLException?不能(检查异常只能缩小或不抛);
- 注意 @Override 注解不是语法必需,但它是编译器帮你守住契约的护栏,漏加可能导致意外覆盖(比如参数类型写错成 Long 而非 long)。
抽象与接口:Java 8 之后怎么选?
别再说“接口定义行为,抽象类定义共性”。现在得看版本、演进性和默认实现成本。
- 接口适合定义能力契约(如 Comparable、Closeable),尤其当多个不相关类需共享行为时;
- 抽象类适合提供通用骨架(如 Spring 的 AbstractController)、共享状态或构造逻辑;
- Java 8+ 默认方法让接口也能提供实现,但注意:不能有状态(无字段)、不能调用 super(除非是 Object 方法)、多个接口冲突时必须显式重写;
- 真实权衡:新加一个通用方法,是往抽象基类加?还是给所有实现类加 default 方法?前者侵入性强,后者易失控 —— Spring 选择抽象类统一管理模板逻辑,MyBatis 则大量用 default 方法降低升级成本。
不复杂但容易忽略:所有 OOP 问题背后,都在考察你能不能把语言特性还原到工程现场——需求变、团队扩、系统老,哪个设计今天省事,明天扛不住。答案没有标准分,但逻辑闭环才有说服力。

















