Appearance
面向对象与设计原则
面向对象三大特性是几乎所有后端面试的开场题,答完三大特性后大概率被追问 SOLID 原则。
Q1: 面向对象的三大(四大)特性是什么? 「🟢 校招/初级」
考察点:OOP 基本功,能否结合代码举例而不是背概念。
参考答案:
- 封装:把数据和操作绑定在一起,对外暴露接口、隐藏内部实现,降低耦合。
- 继承:子类复用父类的属性和方法,建立"is-a"关系;要注意继承层次过深带来的脆弱性,优先"组合优于继承"。
- 多态:同一个接口在不同实现下有不同行为。编译期多态(重载/模板)+ 运行期多态(重写 + 向上转型),是框架"依赖抽象"的基础。
- (有的教材加抽象:提取共性、忽略细节。)
追问延伸:
- 多态在 JVM/运行时层面是怎么实现的?(虚方法表)
- 为什么推荐组合优于继承?
Q2: 重载和重写的区别? 「🟢 校招/初级」
考察点:多态的两种表现形式。
参考答案:
- 重载:同一个类中方法名相同、参数列表不同,编译期确定调用哪个,属于静态多态。
- 重写:子类重新实现父类方法,签名一致,运行期根据实际对象类型分发,属于动态多态。
- 重写时访问权限不能更严格,不能抛出更宽的受检异常。
追问延伸:
- 只有返回值不同能算重载吗?(不能)
- 静态方法能被重写吗?(不能,只能被隐藏)
Q3: 抽象类和接口的区别?什么时候用哪个? 「🟡 中级」
考察点:设计能力,能否说出选型依据。
参考答案:
- 抽象类:可以有构造器、成员变量、已实现方法;表达"is-a",一个类只能继承一个。
- 接口:只定义契约(Java 8 后可有 default 方法);表达"能做什么"(能力),可以多实现。
- 选型:需要复用代码和共享状态用抽象类;需要定义跨类型的行为契约用接口;大多数场景优先接口,面向接口编程。
追问延伸:
- Java 8 的 default 方法和抽象类方法有什么取舍差异?
- Go 没有继承,怎么表达"能力"?(隐式接口)
Q4: 说说 SOLID 五大原则 「🟡 中级」
考察点:面向对象设计的核心素养。
参考答案:
- S 单一职责:一个类只有一个变化的理由。
- O 开闭原则:对扩展开放、对修改关闭,通过抽象和多态实现。
- L 里氏替换:子类能无感知地替换父类,不破坏程序正确性。
- I 接口隔离:客户端不该被迫依赖它不用的接口,宁可多个小接口。
- D 依赖倒置:高层模块依赖抽象,不依赖具体实现;配合依赖注入落地。
追问延伸:
- 举一个违反里氏替换的实际例子?(正方形继承长方形)
- 依赖注入和依赖倒置是一回事吗?
Q5: 什么是依赖注入?控制反转(IoC)又是什么? 「🟡 中级」
考察点:框架设计思想,Spring 面试的铺垫。
参考答案:
- IoC:对象的创建和依赖关系不再由使用方 new,而是交给容器/框架控制,"控制权反转"。
- DI 是 IoC 的一种实现方式:容器把依赖"注入"进来(构造器注入、setter 注入、字段注入)。
- 好处:解耦、便于替换实现、便于单元测试(可以注入 mock)。
追问延伸:
- 构造器注入和字段注入各有什么优缺点?
- Spring 是怎么解决循环依赖的?(三级缓存,见 Spring 篇)
Q6: 解释一下"组合优于继承" 「🟡 中级」
考察点:设计取舍能力。
参考答案:
- 继承是白盒复用,子类能看到父类内部实现,父类一改子类可能跟着坏;且继承关系在编译期固定,无法运行时切换。
- 组合是黑盒复用:持有一个成员对象,只依赖其接口,可以运行时替换实现,耦合更低。
- 典型应用:装饰器模式、策略模式都是用组合替代继承层次。
追问延伸:
List的实现类之间用继承还是组合更合适?- 什么场景下继承仍然是合理选择?