Skip to content

面向对象与设计原则

面向对象三大特性是几乎所有后端面试的开场题,答完三大特性后大概率被追问 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 的实现类之间用继承还是组合更合适?
  • 什么场景下继承仍然是合理选择?