面向对象编程(OOP)核心
❓ 面试官:请用你自己的话解释一下什么是面向对象?它和面向过程有什么区别?
频率:🔥🔥🔥🔥
💡 一句话总结(先抛结论): 面向过程是“编年史”,强调的是一步步去执行事情;面向对象是“人物传记”,强调的是把事物抽象成对象,通过对象之间的交互来完成事情。面向对象最大的优势是易维护、易复用、易扩展。
📝 详细原理解析(举例说明):
- 需求:把大象装进冰箱。
- 面向过程(C 语言风格): 写三个函数:
open(冰箱)->push(大象)->close(冰箱)。关注的是动作流程。 - 面向对象(Java 风格): 抽象出两个对象:
大象和冰箱。冰箱这个对象拥有方法:打开()、装入(大象)、关闭()。关注的是谁拥有什么能力。
❓ 面试官:面向对象的三大特性是什么?能结合业务场景讲讲吗?
频率:🔥🔥🔥🔥🔥
💡 一句话总结(先抛结论): 三大特性是封装、继承、多态。它们是我们写出高内聚、低耦合的优雅代码的基石。
📝 详细原理解析与场景:
封装(Encapsulation):
- 原理:隐藏对象的内部实现细节,只对外暴露特定的接口。把属性私有化(
private),提供公共的getter/setter方法。 - 业务场景:比如
User类的age属性,如果不封装,别人直接写user.age = -10;就出大 Bug 了。封装后,在setAge(int age)方法里就可以加上逻辑判断:如果传的负数就抛出异常,保证了数据的安全性。
- 原理:隐藏对象的内部实现细节,只对外暴露特定的接口。把属性私有化(
继承(Inheritance):
- 原理:子类继承父类的属性和方法,实现代码复用。Java 只支持单继承。
- 业务场景:写电商系统,有普通商品、秒杀商品、团购商品。我们可以抽离出一个
BaseProduct父类(包含商品 ID、名称、基础价格),然后其他商品子类去继承它,省去重复写这些基础字段的功夫。
多态(Polymorphism):
- 原理:同一个接口或父类引用,指向不同子类实例时,调用同一个方法会表现出不同的行为。多态的三个前提:有继承/实现、有方法重写、有父类引用指向子类对象。
- 业务场景(极其重要):支付模块。定义一个
PaymentService接口,里面有个pay()方法。然后写两个实现类WechatPayServiceImpl和AliPayServiceImpl。 在下订单的业务代码里,我们只依赖父接口PaymentService.pay()。至于具体调用哪种支付,运行时通过依赖注入(Spring)决定。以后如果新增银联支付,下订单的核心代码一行都不用改,这就是多态带来的扩展性(符合开闭原则)。
❓ 面试官:接口(Interface)和抽象类(Abstract Class)有什么区别?什么时候该用哪个?【中级】
频率:🔥🔥🔥🔥
💡 一句话总结(先抛结论):
- 抽象类是对事物本质(是什么)的抽象,体现的是
is-a的关系(比如狗是动物); - 接口是对行为能力(能做什么)的抽象,体现的是
has-a / can-do的关系(比如飞机和鸟都能飞)。
📝 详细对比:
| 维度 | 抽象类 (abstract class) | 接口 (interface) |
|---|---|---|
| 继承关系 | 单继承(一个类只能继承一个抽象类) | 多实现(一个类可以实现多个接口) |
| 属性 | 可以有普通成员变量、静态常量 | 只能有 public static final 常量 |
| 方法实现 | 可以有普通方法和抽象方法 | Java 8 以前只能有抽象方法,Java 8 引入了 default 和 static 方法 |
| 设计核心 | 代码复用(自底向上抽象出来的) | 制定规范(自顶向下设计出来的) |
🌟 面试加分项(实战架构设计): "在实际开发中,我们通常会结合使用它们(经典设计模式:模板方法模式)。 比如在写各种定时任务时,我们会先定义一个顶层的接口 JobTask 规范大家都必须实现 execute() 方法。 然后写一个抽象类 BaseJobTask 去实现这个接口,在这个抽象类里写好所有任务通用的逻辑(比如记录日志、计算耗时、异常报警)。 最后,具体的业务任务(比如发短信任务、清理数据任务)去继承抽象类,只专心写自己特有的业务逻辑。这样既有了规范,又极大减少了冗余代码。"
❓ 面试官:重载(Overload)和重写(Override)有什么区别?
频率:🔥🔥🔥
💡 一句话总结(先抛结论):
- 重载发生在同一个类中,方法名相同,但参数列表必须不同(类型、个数、顺序)。它是编译时的多态。
- 重写发生在父子类之间,子类把父类的方法原封不动(方法名、参数列表必须完全相同)重新写一遍业务逻辑。它是运行时的多态。
📝 注意坑点:
- 重载跟方法的返回值类型和修饰符没有任何关系!只看方法名和参数列表。
- 重写有严格的限制(两同两小一大):
- 方法名和参数列表相同。
- 返回值类型必须等于或小于父类的类型(比如父类返回
Object,子类可以返回String)。 - 抛出的异常必须等于或小于父类的异常。
- 访问权限修饰符必须等于或大于父类(比如父类是
protected,子类必须是protected或public)。