Skip to content

面向对象(OOP)是 Java 的根基,封装、继承、多态这三个词天天说,但"多态到底怎么实现的、接口和抽象类到底怎么选"一直没系统梳理。这篇把 OOP 最核心的几块讲清楚,尤其是面试高频的"多态"和"接口 vs 抽象类"。

一、为什么要有面向对象

面向过程(C 语言)是"按步骤写函数",数据和方法分离。项目一大,数据和操作数据的方法散落各处,难维护。面向对象把"数据 + 操作数据的方法"绑成一个对象,用三大特性组织代码:

  • 封装:隐藏内部细节,只暴露接口
  • 继承:复用已有代码
  • 多态:一个接口,多种实现

二、封装:隐藏内部,只暴露接口

封装 = private 字段 + 公开方法,外界不能直接碰内部数据:

java
public class BankAccount {
    private double balance;              // 私有:外部不能直接改

    public void deposit(double amount) { // 公开方法:唯一的入口
        if (amount <= 0) throw new IllegalArgumentException("金额必须 > 0");
        balance += amount;               // 业务校验封装在方法里
    }
    public double getBalance() { return balance; }
}

好处:balance 只能通过 deposit 改,校验逻辑集中在一处,外部改不了脏数据。

三、继承:复用代码

子类 extends 父类,自动拥有父类的字段和方法:

java
public class Animal {
    protected String name;
    public void eat() { System.out.println(name + " 吃东西"); }
}

public class Dog extends Animal {        // Dog 复用 Animal 的 name、eat()
    public void bark() { System.out.println(name + " 汪汪"); }
}

继承解决"代码重复",但注意:Java 是单继承(一个类只能有一个父类),想多"继承"能力要靠接口。

四、多态:一个引用,多种行为(核心)

多态 = 父类引用指向子类对象,运行时调用子类的实现

java
Animal animal = new Dog();   // 编译类型是 Animal,运行类型是 Dog
animal.eat();                // 运行时调用 Dog 的 eat()(如果 Dog 重写了)

// 同一个方法,传不同子类,表现不同
void feed(Animal a) { a.eat(); }   // 传 Dog、Cat 都行,各吃各的

多态的实现机制是"动态绑定":编译时 animal.eat() 不知道调谁,运行时根据对象实际类型(Dog)决定调 Dog 的 eat()

多态的三个条件:继承 / 重写 / 父类引用指向子类,缺一不可。

五、重载 vs 重写(面试高频,别混)

维度重载(Overload)重写(Override)
是什么同方法名,不同参数列表子类覆盖父类方法
发生时机编译期决定(静态多态)运行期决定(动态多态)
参数必须不同必须相同
返回值可不同必须相同(或协变)
java
// 重载:同名方法,参数不同
public void print(int x) { ... }
public void print(String s) { ... }

// 重写:子类覆盖父类
class Animal { void sound() { System.out.println("叫"); } }
class Dog extends Animal { @Override void sound() { System.out.println("汪汪"); } }

六、接口 vs 抽象类(面试必问)

两者都是"抽象",但语义不同:

维度接口(interface)抽象类(abstract class)
语义"能做什么"(能力/协议)"是什么"(共性基类)
继承可实现多个接口只能继承一个(单继承)
成员变量只能 public static final 常量可以有普通成员变量
构造器没有有(子类 super 调用)
方法抽象方法(Java 8 起可有 default)抽象方法 + 具体方法

一句话选型:表达"能力"(会飞、能序列化)用接口;表达"共性"(动物都有名字和吃的方法)用抽象类。需要多继承能力时,接口是唯一选择。

java
// 接口:表达能力
interface Flyable { void fly(); }
interface Swimmable { void swim(); }
class Duck implements Flyable, Swimmable { ... }  // 实现多个接口

// 抽象类:表达共性
abstract class Animal {
    protected String name;                    // 普通成员变量
    abstract void sound();                    // 抽象方法
    void eat() { System.out.println("吃东西"); } // 具体方法
}

小结

  • 封装:private 字段 + 公开方法,隐藏内部
  • 继承:extends 复用代码,Java 单继承
  • 多态:父类引用指向子类,运行时动态绑定(继承 + 重写 + 父类引用)
  • 重载 = 编译期(同方法名不同参数);重写 = 运行期(子类覆盖父类)
  • 接口表达"能力"(多实现),抽象类表达"共性"(单继承)

OOP 是写 Java 的基本功。想了解 OOP 之上怎么用这些特性组织代码,看「架构设计 → 设计模式」——设计模式就是 OOP 三大特性的组合套路。