跳转至

面向对象的 3、5 知识点

前言

前面已经讲了 Java 的类和对象的概念,接下来我们看看Java 里边的一个核心思想 - 面向对象编程

什么是面向对象?

所谓面向对象,是一种通过对象的方式,将现实中的事物映射到计算机模型的一种编程方法。

对象的含义指的是具体的某一个事物,即我们在现实生活中能够看得见摸得着的。在面向对象程序设计中,对象指的是计算机系统中的某一个成分,主要有两层含义。一个是指 数据,另一个则是动作。即对象是两者的结合体,通过对象不仅能够进行操作,还能对操作的结果进行记录。

在这之前,另一种编程方式是面向过程,用一个具体的例子来讲,可以描述成下面这样:

假如有一天你很想吃酸菜鱼那么你该怎么办呢下面就以面向对象和面向过程给你两个选择让你决定来选哪一个

1. 面向对象打开手机打开外卖软件搜索酸菜鱼然后下单等着外卖送到家就行
2. 面向过程先去买菜酸菜调料……,然后回家杀鱼切酸菜切调料……,再接着开始炒最后做好盛到盘子里

对比可以发现两者的优缺点:

  • 面向过程
    • 优点:性能好;以例子来说自己做比起点外卖,经济又实惠,还吃得放心。
    • 缺点:不易维护、不易复用、不易扩展;以例子来讲,要是我们自己做,临时又想吃其他的菜,又得跑去买材料啥的,麻烦!但外卖就不一样了,直接打开手机再点就是。
  • 面向对象
    • 优点:易维护、易复用、易扩展,也就是面向过程的缺点。
    • 缺点:性能较差;比起自己做,点外卖成本啥的可能就比较高了。

面向对象的 5 大原则

  1. 单一职责原则 SRP
    又称为单一功能原则,也就是说类的功能要单一,不能太复杂。
    举个例子来说,学校里边有学生、老师、管理员,如果将这些人统一封装在一个类中,那么到时候难以对他们的身份作区分,那么此时按照 SRP 原则,我们就可以将他们各自分为一个类,从而方便管理。
  2. 开放封闭原则 OCP
    指一个模块对于扩展是开放的,但对于修改则是封闭的。也就是说可以增加功能,但是不能修改功能。
    也就是说,一个类可以进行扩展(添加属性或者方法),但是对于类中已有的属性和方法,不要修改它们。
  3. 里氏替换原则 LSP
    指子类能够替换父类出现在父类能够出现的任何地方。
    假设有两个类 Father 和 Child,其中 Father 是 Child 的父类,那么在进行调用时,Father 类可以引用 Child 类,反之却不行。
  4. 依赖倒置原则 DIP
    高层次的模块不应该依赖于低层次的模块,而应该都依赖于抽象。抽象不应该依赖于具体实现,但具体实现应该依赖于抽象。
    也就是说,我们可以将同类事物的共性抽取出来,将其作为这一类事物的“高层次模块”,然后由“低层次模块”来继承或者实现“高层次模块”。
  5. 接口分离原则 ISP
    指设计时可以采用多个与特定客户类相关的接口,而不是采用一个通用的接口。

面向对象的 3 大特性

封装(Encapsulation)

封装的核心思想是

把“属性”和“行为”捆在一起,用方法控制访问权限。

比如我们想创建一个“英雄 Hero”对象,它有名字、技能。 我们不希望别人直接乱改内部属性,而是通过“方法”来操作。

public class Hero {
    private String name;   // 名字
    private String skill;  // 技能

    // 提供外部访问方法
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

    public String getSkill() {
        return skill;
    }
    public void setSkill(String skill) {
        this.skill = skill;
    }
}

解释:

  • private:隐藏内部细节,外部无法直接访问;
  • getXxx() / setXxx():提供安全访问通道;
  • 这样可以控制数据修改的逻辑,提高安全性。

通俗理解:

你去银行办业务时,只能通过“窗口(方法)”操作账户,不能直接进金库乱改钱,这就是“封装”。


继承(Inheritance)

继承是“复用”的核心,让我们可以不用重复写相似代码。

子类可以自动拥有父类的属性和方法,还可以自己扩展新的功能。

示例:

// 父类:英雄
public class Hero {
    String name;
    public void attack() {
        System.out.println(name + " 发起普通攻击!");
    }
}

// 子类:射手
public class Shooter extends Hero {
    public void skill() {
        System.out.println(name + " 发动远程射击!");
    }
}

使用:

Shooter s = new Shooter();
s.name = "后羿";
s.attack(); // 继承自父类
s.skill();  // 子类自己定义

输出:

后羿 发起普通攻击!
后羿 发动远程射击!

向上转型(Upcasting)

Hero hero = new Shooter(); // 父类引用指向子类对象
hero.attack();  // ✅ 可以
hero.skill();   // ❌ 不能访问子类特有方法

因为此时 hero 的类型是 Hero,编译器只能识别父类的功能。

注意:

  • Java 只支持单继承(一个类只能有一个父类)。
  • 但可以通过 “多层继承” 或 接口实现(implements) 来实现复用。
  • 子类不能继承父类的 private 成员。

通俗比喻:

继承就像孩子继承了父母的“DNA”。
你会有父母的特征(属性),还能发展自己的技能(方法)。

重写(Override)

  • 概念: 是指子类重新定义父类中已经存在的方法。要求方法名、参数列表、返回类型完全一致。 目的是修改或扩展父类方法的行为。
  • 特点:
特点 说明
定义位置 父子类之间的子类中
方法名 必须相同
参数列表 必须相同
返回类型 必须相同或是父类返回类型的子类(协变返回类型)
访问修饰符 不能比父类更严格
异常类型 子类不能抛出比父类更广的异常
调用方式 通过多态:父类引用指向子类对象
class Hero {
    public void fight() {
        System.out.println("战斗");
    }
}
class Shooter extends Hero {
    @Override
    public void fight() {
        System.out.println("远程战斗");
    }
}
  • 注意事项:

    • 使用 @Override 注解可帮助编译器检测是否正确重写。
    • private、static、final 方法不能被重写。
    • 构造方法不能被继承或重写。
    • 重写方法访问级别不能更低,例如:
      • public → protected → default → private
      • 子类不能比父类“更严格”。


多态(Polymorphism)

多态: 同一种操作,对不同对象会表现出不同的行为。
“同一个方法,不同对象执行时表现不同。”

示例:

class Hero {
    public void attack() {
        System.out.println("普通攻击!");
    }
}

class Shooter extends Hero {
    @Override
    public void attack() {
        System.out.println("远程射击!");
    }
}

class Mage extends Hero {
    @Override
    public void attack() {
        System.out.println("释放魔法!");
    }
}

使用:

Hero h1 = new Shooter();
Hero h2 = new Mage();

h1.attack(); // 输出:远程射击!
h2.attack(); // 输出:释放魔法!

原理解释:

父类引用可以指向子类对象(向上转型);
运行时根据对象实际类型决定调用哪个方法;

这就是 “运行时多态”(Runtime Polymorphism)。

成员变量 vs 成员方法的调用规则:

类型 编译期看谁 运行期看谁
成员变量 看左边(父类) 看左边(父类)
成员方法 看左边(父类) 看右边(子类)

例子:

class Hero {
    String name = "Hero";
    public void show() { System.out.println("父类方法"); }
}

class Shooter extends Hero {
    String name = "Shooter";
    public void show() { System.out.println("子类方法"); }
}

Hero h = new Shooter();
System.out.println(h.name); // 输出:Hero
h.show();                   // 输出:子类方法

多态的三大必要条件:

  • 继承(extends / implements)
  • 方法重写(Override)
  • 父类引用指向子类对象

编译时多态 vs 运行时多态

类型 实现方式 发生阶段
编译时多态 方法重载(Overload) 编译阶段
运行时多态 方法重写(Override) 运行阶段

注意事项:

多态下不能访问子类特有属性或方法;
如果需要访问,必须 向下转型:

Hero h = new Shooter();
((Shooter)h).skill();

若转型错误,会抛出 ClassCastException。

通俗比喻:

“父类是接口,子类是不同的实现。” 比如“动物都会叫”,但猫喵喵叫、狗汪汪叫、鸟叽叽叫—— 这就是“多态”。

✅ 总结对比表

特性 关键字 目的 示例 优势
封装 private / get / set 隐藏细节 银行账户操作 安全、可维护
继承 extends 代码复用 Hero → Shooter 减少重复
多态 override / upcasting 灵活扩展 Hero h = new Shooter() 可扩展性高

一句话总结:

封装 让代码更安全,
继承 让代码更复用,
多态 让代码更灵活。

总结

以上就是关于面向对象编程思想的一些简单知识介绍了,主要讲了面向对象的概念,面向对象的 3 大特性以及面向对象的 5 大原则