面向对象编程(OOP)通用跨语言笔记

本笔记剥离 Java、Python、C++、C#、JavaScript 等语言的语法差异,聚焦 OOP 的核心思想、通用规则与设计本质,通过生活化类比降低抽象概念的理解门槛,同时标注新手易错点与通用代码示例,实现「学透通用逻辑,快速适配任意 OOP 语言」的目标。


第一部分 OOP 基础认知篇

1.1 面向对象编程核心定义

核心本质

OOP 是一种以「对象」为核心的编程范式,它将现实世界的实体抽象为程序中的「类」与「对象」,把实体的静态特征(数据)和动态行为(逻辑)封装在一起,是对现实世界逻辑的直接映射。

  • 核心设计哲学:万物皆对象。现实中所有实体(人、汽车、手机)都可以抽象为程序中的对象,每个对象都有自己的特征和能做的事。
  • 核心解决目标:从根本上提升代码的复用性、可维护性、可扩展性、可阅读性,解决大型复杂系统的迭代难题。
通俗类比

你要做一个「奶茶店系统」:

  • 现实世界里,奶茶、杯子、顾客、收银员都是独立的实体,每个实体有自己的特征和行为;
  • OOP 就是把这些实体直接搬到代码里,先定义好每个实体是什么、能做什么,再让它们互相交互完成点单、制作、结账的全流程,而不是只盯着「点单的步骤」写代码。

1.2 OOP vs 面向过程编程(POP)

面向过程是 OOP 的基础,二者不是对立关系,而是设计思路的核心差异,OOP 完全兼容 POP 的逻辑。

核心差异对比表
通俗类比
  • POP 做蛋炒饭:核心是步骤,按顺序执行:拿锅→倒油→打鸡蛋→放米饭→翻炒→调味→出锅,全程围绕「炒饭的流程」展开。
  • OOP 做蛋炒饭 :核心是实体,先定义每个参与的对象:
    • 锅:属性(材质、大小),行为(加热、盛取)
    • 鸡蛋:属性(重量、新鲜度),行为(打散、煎熟)
    • 米饭:属性(软硬、分量),行为(翻炒、入味)再让这些对象互相交互,完成炒饭的全流程。
  • 互补性:OOP 中,每个对象的方法内部,依然是用 POP 的线性步骤实现的,二者完全兼容。

1.3 OOP 的通用适用与不适用场景

高适配场景(OOP 优势最大化)
  • 企业级业务系统(电商、ERP、CRM 等,实体多、逻辑复杂、迭代频繁)
  • GUI 桌面应用、移动端 APP(按钮、窗口、输入框都是天然的对象)
  • 游戏开发(玩家、NPC、怪物、道具、技能全是对象,迭代扩展需求极强)
  • 通用框架、组件库设计(需要高复用、高扩展,适配不同业务场景)
  • 大型团队协作项目(通过类的封装与接口规范,实现多人并行开发)
低适配场景(OOP 会增加冗余开销,收益极低)
  • 高性能计算(矩阵运算、数值模拟等,核心是线性计算逻辑,无实体可抽象)
  • 一次性脚本工具(简单的文件处理、数据清洗,线性执行即可完成)
  • 资源极度受限的嵌入式场景(单片机、低算力设备,OOP 的内存开销无法接受)

总结


第二部分 OOP 核心基石:类与对象

类与对象是 OOP 的最小单元,所有 OOP 语言的核心定义完全通用,仅语法实现有差异,是理解 OOP 的第一门槛。

2.1 类与对象的通用核心定义

核心定义
  • 类(Class) :对一类实体的共性抽象模板,定义了该类实体统一的属性与行为规范,本身不占用实际内存,只定义「规则」。
  • 对象 / 实例(Object/Instance):类的具体实现个体,是类模板实例化后的产物,拥有独立的内存空间与专属数据,是程序中真正干活的主体。
  • 核心关系:一对多的模板与实例关系,一个类可以创建无数个相互独立的对象,互不影响。
通俗类比(新手必懂)
  • 类 = 月饼模具,定义了月饼的形状、花纹、尺寸(属性规范),以及「压出月饼」的能力(行为规范)。模具本身不能吃,也不占月饼的存储空间,但它决定了所有月饼的基础规则。
  • 对象 = 用这个模具压出来的一个个具体的月饼,每个月饼有自己的馅料、重量、生产日期(独立数据),你吃掉一个月饼,不影响模具和其他月饼。

2.2 类的通用组成成员

所有 OOP 语言的类,都由这 4 类核心成员构成,仅语法命名有差异:

通用名称 语言别名 核心定义 通俗类比
属性 字段、成员变量 对象的静态特征,用于存储对象的数据 月饼的馅料、尺寸、重量;人的姓名、年龄、身高
方法 成员函数 对象的动态行为,用于封装对象的可执行逻辑 月饼能被加热、食用;人能吃饭、走路、说话
构造方法 构造函数 对象实例化时自动执行的方法,核心作用是完成对象的初始化 压月饼的瞬间,给月饼定馅料、重量、生产日期,不用你手动再单独设置
析构方法 销毁方法 对象生命周期结束时自动执行的方法,核心作用是完成资源清理与内存释放 月饼被吃完 / 过期后,清理包装、扔进垃圾桶,释放占用的空间

2.3 对象的通用核心操作

1. 对象实例化

通过类创建对象的过程,本质是:为对象分配堆内存 → 执行构造方法完成初始化 → 返回对象的内存引用地址。

  • 通用语法示例(跨语言对照): java

    java 复制代码
    // Java 实例化
    Student zhangSan = new Student();

    python

    python 复制代码
    # Python 实例化
    zhang_san = Student()

    cpp

    cpp 复制代码
    // C++ 实例化
    Student zhangSan;
2. 成员访问

通过对象的引用,完成属性的读取 / 修改、方法的调用,是对象交互的核心方式。

  • 通用语法示例: java

    java 复制代码
    // 读取属性
    System.out.println(zhangSan.name);
    // 修改属性
    zhangSan.age = 20;
    // 调用方法
    zhangSan.study();
3. 对象的核心对比规则(跨语言通用逻辑,新手高频踩坑)

所有 OOP 语言的对象对比,都分为两个完全不同的维度,新手极易混淆:

表格

对比类型 核心本质 通俗理解 语言实现示例
内存地址对比 对比两个引用是不是指向堆内存里的同一个对象 是不是同一个月饼,而不是两个长得一样的月饼 Java ==、Python is
内容数据对比 对比两个对象的属性值是不是完全一致 两个月饼的馅料、重量、尺寸是不是一模一样 Java equals()、Python ==
4. 对象的销毁

核心流程:解除所有指向该对象的引用 → 被垃圾回收器(GC)标记为可回收 → 执行析构方法完成资源清理 → 释放堆内存。

2.4 通用核心关键字:this/self

通用本质

指代当前正在执行方法的对象实例本身 ,相当于现实中的「我自己」,所有 OOP 语言都有这个关键字,仅命名不同(Java/C++/C# 用this,Python 用self)。

通用核心用法(全语言通用)
  1. 区分成员变量与局部变量 (最常用)解决「方法内的局部变量和类的成员变量重名」的问题,this.xxx明确指代当前对象的成员变量。

    java

    java 复制代码
    public class Student {
        private String name; // 成员变量
        // 构造方法的局部变量name和成员变量重名
        public Student(String name) {
            this.name = name; // 把局部变量的值,赋值给当前对象的成员变量
        }
    }

    python

    python 复制代码
    class Student:
        def __init__(self, name):
            self.name = name # self.name是对象的成员变量,name是局部变量
  2. 在类的内部,调用当前对象的其他方法 / 属性

    java

    java 复制代码
    public void study() {
        System.out.println(this.name + "正在学习");
        this.doHomework(); // 调用当前对象的另一个方法
    }
  3. 构造方法之间的互相调用

    java

    java 复制代码
    public class Student {
        // 无参构造
        public Student() {
            this("未知姓名", 0); // 调用本类的有参构造
        }
        // 有参构造
        public Student(String name, int age) {
            this.name = name;
            this.age = age;
        }
    }
  4. 把当前对象作为参数,传递给其他方法

    java

    java 复制代码
    public void sendMessage(Teacher teacher) {
        teacher.receiveMessage(this); // 把当前学生对象,传给老师的接收消息方法
    }
新手易错点
  • 误以为this/self是类本身,它永远指代当前正在执行方法的对象实例,不是类模板。
  • 静态方法中不能使用this/self,因为静态方法属于类,执行时可能还没有创建对象实例。

第三部分 OOP 三大核心特性(灵魂)

3.1 封装(Encapsulation)

核心定义与设计目标
  • 定义:隐藏对象的内部实现细节,仅对外暴露安全、可控的访问接口,外部只能通过暴露的接口操作对象,无权修改内部核心逻辑。
  • 核心目标:
    1. 保护数据安全,防止外部随意修改核心属性导致数据异常;
    2. 降低代码耦合,内部实现修改时,只要接口不变,外部调用代码无需改动;
    3. 隔离变化,把不稳定的内部逻辑封装起来,对外提供稳定的接口;
    4. 提升代码可维护性,外部无需关心内部实现,只需要知道接口怎么用。
通俗类比(新手必懂)

封装就是我们日常用的电视机

  • 电视机把内部的电路板、芯片、线路、电压控制逻辑全部隐藏在外壳里(私有,外部不可见),你不能直接碰,不然会触电或者烧坏电视;
  • 对外只暴露遥控器上的按钮(公开接口),你只需要按开机、换台、调音量,就能正常使用电视,完全不需要知道内部的电路是怎么实现的;
  • 就算电视机内部的芯片换了,只要遥控器的按钮功能不变,你的使用方式完全不用改,这就是封装的核心价值。
通用实现核心:访问权限控制

OOP 通过三级访问级别,实现封装的粒度控制,这是跨语言的通用思想,仅语法关键字有差异:

通用访问级别 核心权限范围 通俗类比 通用使用原则
公开级别(public) 对外完全暴露,任何外部代码均可访问 电视机遥控器的按钮,所有人都能按 仅对外暴露必须的接口,越少越好
受保护级别(protected) 仅类内部与子类可访问,外部不可访问 电视机的维修口,只有厂家(自己)和售后(子类)能打开 仅给子类预留的扩展接口使用
私有级别(private) 仅类内部可访问,子类与外部均不可访问 电视机内部的芯片,只有电视机自己能操作 所有核心属性、内部实现逻辑,全部私有
通用实现范式:属性私有化 + 公共访问 / 修改方法(getter/setter)

这是封装最经典的实现方式,核心是:把所有核心属性设为私有,禁止外部直接访问,仅通过公开的 getter(读取)、setter(修改)方法操作属性,在方法内添加校验逻辑,保证数据安全。

代码示例

java

java 复制代码
public class Student {
    // 核心属性全部私有化,外部无法直接访问
    private String name;
    private int age;

    // 公开的getter方法,仅允许读取姓名
    public String getName() {
        return this.name;
    }

    // 公开的setter方法,仅允许修改姓名,可添加非空校验
    public void setName(String name) {
        if (name == null || name.isEmpty()) {
            throw new IllegalArgumentException("姓名不能为空");
        }
        this.name = name;
    }

    // 公开的getter方法,读取年龄
    public int getAge() {
        return this.age;
    }

    // 公开的setter方法,修改年龄,添加合法性校验
    public void setAge(int age) {
        if (age < 0 || age > 150) {
            throw new IllegalArgumentException("年龄必须在0-150之间");
        }
        this.age = age;
    }
}
封装的通用最佳实践
  1. 最小权限原则:能私有就不保护,能保护就不公开,永远给成员最小的访问权限。
  2. 禁止直接对外暴露可变的核心属性,必须通过 getter/setter 控制访问。
  3. 封装行为,而非仅封装数据:OOP 的封装是把数据和操作数据的行为封装在一起,不是把数据藏起来只提供 get/set,那不是真正的封装。
  4. 一个类只对外暴露最少的必要接口,内部实现细节全部隐藏。
新手易错点
  • 把所有属性都设为 public,完全不封装,导致数据可以被外部随意修改,出现异常无法定位。
  • 写了 getter/setter,但里面没有任何校验逻辑,等于白写,完全没起到封装的作用。
  • 过度封装,把简单的逻辑拆得支离破碎,反而降低了代码可读性。

3.2 继承(Inheritance)

核心定义与设计目标
  • 定义:基于已有的父类(基类 / 超类) 创建新的子类(派生类),子类自动复用父类的非私有属性与方法,无需重复编写相同代码。
  • 核心目标:
    1. 实现代码复用,把多个子类的共性代码提取到父类,一处修改,所有子类生效;
    2. 建立类的层级体系,实现现实世界中「is-a」的实体关系(比如「狗是动物」「学生是人」);
    3. 为多态提供实现基础。
通俗类比(新手必懂)

继承就是现实中的父子遗传

  • 父亲(父类)有身高、肤色的属性,有吃饭、走路、呼吸的方法;
  • 儿子(子类)天生就继承了父亲的这些特征和能力,不用再重新学习一遍吃饭、走路;
  • 同时,儿子还可以拥有自己独有的属性和能力(比如会弹钢琴、会编程),还可以把父亲的「走路」方法改得更帅气(方法重写)。
继承的通用核心规则(全语言通用)
  1. 子类可自动复用父类的非私有成员,父类的私有属性 / 方法,子类无法直接访问。
  2. 子类可扩展独有的属性与方法,实现个性化能力。
  3. 子类可重写父类的非私有方法,实现自定义的业务逻辑。
  4. 子类构造方法必须优先调用父类的构造方法 :子类初始化时,必须先完成父类的初始化,再初始化自己的独有成员,就像先有父亲,才有儿子。
    • 通用实现:通过super关键字调用父类构造方法,若未手动调用,编译器会自动调用父类的无参构造。
通用的继承类型
继承类型 核心定义 语言支持 通俗类比
单继承 一个子类仅能继承一个父类 Java、C#、JavaScript(ES6+) 一个儿子只能有一个亲生父亲
多继承 一个子类可同时继承多个父类 Python、C++ 一个孩子可以同时继承父亲和母亲的特征
多层继承 形成继承链,子类的父类也继承自其他类 全语言支持 爷爷→父亲→儿子→孙子,形成家族继承链
继承中的通用核心问题
  1. 方法重写的规则约束 子类重写父类方法时,必须保证方法名、参数列表、返回值类型完全一致,否则就不是重写,而是重载。同时,子类方法的访问权限不能低于父类,不能抛出比父类更宽泛的异常。

  2. 多继承的菱形继承(钻石继承)问题问题场景:A 是父类,B 和 C 都继承 A,D 同时继承 B 和 C,此时 D 中继承的 A 的方法,到底用 B 的实现还是 C 的实现?会出现逻辑歧义。

    • 通用解决方案:
      1. 单继承语言(Java):直接禁止多继承,用接口替代;
      2. 多继承语言(Python):通过 MRO(方法解析顺序)算法,明确规定方法的查找优先级,避免歧义。
  3. super 关键字的通用逻辑 super的本质是指代当前对象的父类实例,通用用法:

    • 调用父类的构造方法(必须放在子类构造方法的第一行);
    • 调用父类的普通方法,解决子类重写父类方法后,想调用父类原有实现的问题。
继承的通用使用禁忌(新手必看)
  1. 禁止为了单纯复用代码而使用继承 :这是新手最容易踩的坑!如果两个类之间没有「is-a」的关系,只是有部分代码重复,优先用组合 ,而不是继承。
    • 反例:汽车需要用到轮子的功能,让汽车继承轮子类,完全违背现实逻辑;
    • 正解:汽车类里持有一个轮子类的对象,调用轮子的方法(组合),就像人需要用手机,不是继承手机,而是拿着手机用。
  2. 禁止过深的继承层级,建议不超过 3 层,否则代码可读性极差,找一个方法要翻好几层父类,维护成本极高。
  3. 禁止违背里氏替换原则的继承设计:子类不能破坏父类的原有业务逻辑,所有父类能使用的地方,子类必须能透明替换使用。

3.3 多态(Polymorphism)

核心定义与设计目标
  • 定义:同一个行为 / 接口,在不同场景下拥有不同的实现效果,是 OOP 的灵魂,也是 OOP 最强大的特性。
  • 核心目标:
    1. 极致降低代码耦合,上层代码仅依赖抽象,不依赖具体实现;
    2. 极致提升程序扩展性,新增功能无需修改原有代码,完美符合开闭原则;
    3. 消除大量冗余的 if-else 分支判断,让代码更简洁、更易维护。
通俗类比(新手必懂)

多态就是同一个指令,不同的对象有完全不同的反应

  • 你对着一群动物喊一声「叫」:
    • 狗会执行「汪汪汪」的实现;
    • 猫会执行「喵喵喵」的实现;
    • 鸡会执行「咯咯咯」的实现;
  • 同一个行为「叫」,不同的对象有不同的实现效果,这就是多态。
  • 你不需要关心面前的具体是狗还是猫,只需要喊「叫」就行,后续新增一个鸭子,只需要让它继承动物类,实现「叫」的方法,原来的代码完全不用改,就能正常执行。
多态的通用实现前提(三个必须同时满足,缺一不可)
  1. 存在继承 / 接口实现关系(比如狗、猫都继承动物类);
  2. 子类重写了父类 / 接口的方法(狗、猫都重写了「叫」的方法);
  3. 父类引用 / 接口指向子类实例对象 (比如Animal animal = new Dog();)。
多态的两种通用形态
1. 编译时多态(静态多态)
  • 定义:在程序编译阶段就确定执行逻辑的多态,编译期就能明确要调用的方法。
  • 通用实现:方法重载(同一个类中,多个同名但参数列表不同的方法)。
  • 通俗类比:同一个人,有多个打招呼的方式,你可以说「你好」,也可以说「你好,张三」,也可以说「你好,张三,很高兴认识你」,都是「打招呼」这个行为,编译的时候就根据你传的参数,确定要调用哪个方法。
2. 运行时多态(动态多态)
  • 定义:在程序运行时才确定执行逻辑的多态,编译期只知道父类引用,运行时才知道具体指向的子类实例,是OOP 多态的核心
  • 通用实现:方法重写 + 动态绑定(迟绑定),程序运行时,根据引用指向的实际对象,动态绑定对应的方法实现。
  • 通俗类比:你提前录好了一句「叫」的指令,编译的时候只知道是给动物听的,运行的时候,才知道面前的是狗还是猫,然后执行对应的叫声。
代码示例(运行时多态,核心)

java

java 复制代码
// 父类:动物
public abstract class Animal {
    // 抽象方法:叫
    public abstract void shout();
}

// 子类:狗
public class Dog extends Animal {
    @Override
    public void shout() {
        System.out.println("汪汪汪");
    }
}

// 子类:猫
public class Cat extends Animal {
    @Override
    public void shout() {
        System.out.println("喵喵喵");
    }
}

// 测试类
public class Test {
    public static void main(String[] args) {
        // 父类引用指向子类实例,核心!
        Animal dog = new Dog();
        Animal cat = new Cat();
        
        // 同一个行为shout(),不同的实现效果
        dog.shout(); // 运行时执行Dog的shout,输出:汪汪汪
        cat.shout(); // 运行时执行Cat的shout,输出:喵喵喵
    }
}
多态的通用核心优势
  1. 扩展性极强:新增一个鸭子类,只需要继承 Animal,实现 shout () 方法,原有测试代码完全不用修改,完美符合开闭原则。

  2. 代码极度简洁 :消除大量冗余的 if-else 分支。

    • 不用多态的写法: java

      java 复制代码
      // 冗余的if-else,新增动物就要加分支,违反开闭原则
      public void animalShout(String type) {
          if ("dog".equals(type)) {
              System.out.println("汪汪汪");
          } else if ("cat".equals(type)) {
              System.out.println("喵喵喵");
          }
      }
    • 用多态的写法: java

      java 复制代码
      // 无if-else,新增动物无需修改代码
      public void animalShout(Animal animal) {
          animal.shout();
      }
  3. 耦合度极低:上层代码仅依赖 Animal 这个抽象父类,不依赖具体的 Dog、Cat 实现,修改 Dog 的 shout 实现,完全不影响上层调用代码。

新手易错点
  • 误以为只要重写了方法就是多态,必须满足「父类引用指向子类实例」这个核心前提,否则只是方法重写,没有多态的效果。
  • 混淆方法重载和重写,把编译时多态当成 OOP 多态的核心,实际上运行时多态才是 OOP 的灵魂。
  • 重写方法时,修改了方法名或参数列表,导致变成了重载,多态逻辑完全失效。

第四部分 OOP 进阶通用核心概念

4.1 抽象(Abstraction)

核心定义

抽象是 OOP 的底层核心思想,本质是:忽略实体的非核心细节,提取共性特征与行为,定义统一的规范,只关注对象能做什么,不关注它具体怎么做。

  • 通俗类比:你要设计一个打车软件,对于「司机」这个实体,你不需要关心他的头发颜色、身高、爱好,只需要提取他的核心共性:有驾照、有车、能接单、能开车,这就是抽象。
  • 抽象的两个通用维度:
    1. 数据抽象:提取实体的共性属性,定义数据规范(比如司机的驾照、车辆信息);
    2. 行为抽象:提取实体的共性行为,定义方法接口(比如司机的接单、开车行为)。
  • 通用实现载体:抽象类、接口。

4.2 抽象类(Abstract Class)

通用核心定义

被 abstract 修饰的、不能被实例化的类,仅作为子类的通用模板,可同时包含抽象方法(只有方法签名,没有实现)与具体实现方法。

  • 通俗类比:抽象类就是「动物」这个概念,世界上没有一个具体的东西叫「动物」,只有狗、猫、鸟这些具体的动物,所以「动物」不能被实例化,只能作为模板,给所有具体的动物子类继承,定义所有动物都必须有的规范。
通用核心规则
  1. 包含抽象方法的类,必须定义为抽象类;
  2. 子类继承抽象类,必须实现所有抽象方法,否则子类也必须定义为抽象类;
  3. 可拥有构造方法,供子类实例化时调用;
  4. 可包含成员变量、具体方法、静态方法,和普通类的能力基本一致,唯一区别是不能被实例化。
通用使用场景

提取多个子类的共性代码 ,同时定义子类必须实现的强制规范。比如:

  • 多个支付方式(微信支付、支付宝支付)都有共同的属性(支付金额、订单号)和共同的具体方法(生成支付单号),同时有必须强制实现的抽象方法(支付、退款),就可以定义一个支付抽象类。

4.3 接口(Interface)

通用核心定义

行为的契约与规范,仅定义方法的签名(名称、参数、返回值),不包含具体实现逻辑,代表一种「can-do」的能力规范,实现了接口的类,就代表拥有了对应的能力,必须遵守契约,实现接口的所有方法。

  • 通俗类比:接口就是「会飞」这个能力证书,定义了「fly ()」这个行为规范。鸟可以实现这个接口,飞机可以实现这个接口,超人也可以实现这个接口,它们不是一类东西,但是都有「飞」这个能力,都必须遵守「飞」的契约。
通用核心规则
  1. 接口不能被实例化;
  2. 实现类必须实现接口中定义的所有方法;
  3. 一个类可同时实现多个接口(多实现),不受单继承限制;
  4. 接口之间可存在继承关系,一个接口可以继承多个其他接口。
抽象类 vs 接口:通用核心区别表(新手必懂)
维度 抽象类 接口
核心定位 同类实体的共性模板,代表「is-a」的关系 行为能力的契约规范,代表「can-do/like-a」的关系
方法实现 可同时包含抽象方法与具体实现方法 仅定义方法规范,无具体实现(Java 8 + 可默认方法)
继承 / 实现 受单继承限制,一个子类只能继承一个抽象类 支持多实现,一个类可同时实现多个接口
状态存储 可定义普通成员变量,存储对象的状态 不可定义普通成员变量,仅可定义常量
构造方法 可拥有构造方法,供子类调用 不能拥有构造方法
新手易错点

混淆抽象类和接口的使用场景,核心判断标准:

  • 如果是同类实体,有「is-a」的关系,需要复用共性代码,用抽象类;
  • 如果是不同类的实体,只是有共同的能力,有「can-do」的关系,用接口。

4.4 实例成员 vs 静态成员

这是新手高频混淆的概念,核心区别是「属于对象,还是属于类本身」。

实例成员(对象成员)
  • 通用定义:属于具体对象实例的成员,每个实例拥有独立的副本,一个实例修改了实例成员,不影响其他实例。
  • 核心规则:必须先实例化创建对象,才能通过对象访问。
  • 包含:实例属性、实例方法。
  • 通俗类比:每个学生自己的考试分数,每个学生的分数都是独立的,张三考了 90 分,不影响李四的分数。
静态成员(类成员)
  • 通用定义:属于类本身的成员,被该类的所有实例共享,仅在类加载时初始化一次,内存中只有一份。
  • 核心规则:无需实例化对象,直接通过类名即可访问。
  • 包含:静态属性、静态方法、静态代码块。
  • 通俗类比:一个班级的班主任,所有学生共享同一个班主任,不管有多少个学生,班主任只有一个。
代码示例

java

java 复制代码
public class Student {
    // 实例属性:每个学生独立的姓名、年龄
    private String name;
    private int age;
    // 静态属性:所有学生共享的班级名称,仅初始化一次
    public static String className = "计算机一班";
    // 静态常量:全局共享的常量,不可修改
    public static final String SCHOOL_NAME = "XX大学";

    // 实例方法:属于对象,可访问实例成员和静态成员
    public void study() {
        System.out.println(this.name + "在" + className + "学习");
    }

    // 静态方法:属于类,只能访问静态成员,不能直接访问实例成员
    public static String getClassName() {
        return className;
        // 错误:不能直接访问this.name,因为还没有实例化对象
    }
}

// 调用方式
public class Test {
    public static void main(String[] args) {
        // 静态成员:直接通过类名访问,无需实例化
        System.out.println(Student.className);
        System.out.println(Student.getClassName());

        // 实例成员:必须先实例化对象,才能访问
        Student zhangSan = new Student();
        zhangSan.study();
    }
}
通用使用场景与禁忌
  • 适用场景:全局常量、工具方法、统计实例个数的共享数据、所有实例共享的配置信息。
  • 绝对禁忌:
    1. 禁止用静态成员存储对象的个性化状态,会导致所有实例的数据混乱;
    2. 静态方法中不可直接访问实例成员,因为静态方法加载时,实例可能还未创建;
    3. 禁止把本该实例化的业务逻辑,强行写成静态工具类,导致代码无法扩展、无法测试。

4.5 方法重载 vs 方法重写

新手 100% 会混淆的核心概念,跨语言规则完全一致,必须彻底分清。

维度 方法重载(Overload) 方法重写 / 覆盖(Override)
核心定义 同一个类中,定义多个同名但参数列表不同的方法 子类中定义与父类方法名、参数列表、返回值完全一致的方法,覆盖父类的原有实现
定义位置 同一个类内部 继承关系的父子类之间
方法签名要求 方法名相同,参数列表(个数、类型、顺序)必须不同 方法名、参数列表、返回值必须完全一致
多态类型 编译时多态(静态多态) 运行时多态(动态多态)
核心规则 与返回值类型、访问权限无关,仅看参数列表 子类方法的访问权限不能低于父类,不能抛出比父类更宽泛的异常
核心目的 实现同一个行为的多种参数适配,提升代码易用性 子类自定义父类方法的实现,为多态提供基础
通用易错点
  1. 误以为返回值类型不同就是重载,重载只看参数列表,和返回值、访问权限无关,编译会报错。
  2. 重写方法时,不小心写错了方法名、参数个数 / 类型,结果变成了重载,不是重写,导致多态逻辑完全失效。
  3. 子类重写父类方法时,把访问权限改得更低(比如父类是 public,子类改成 private),编译会直接报错。

4.6 对象生命周期与内存管理通用逻辑

对象通用生命周期阶段

创建 → 初始化 → 使用 → 销毁,全 OOP 语言通用,仅垃圾回收机制有差异。

  1. 创建 :程序执行new关键字,申请堆内存空间;
  2. 初始化:执行构造方法,给对象的属性赋值,完成初始化;
  3. 使用:通过对象引用,访问属性、调用方法,完成业务逻辑;
  4. 销毁:解除所有指向该对象的引用,被垃圾回收器标记,执行析构方法,释放堆内存。
通用内存管理核心逻辑
内存区域 存储内容 生命周期 释放方式
栈内存 对象的引用地址、方法的局部变量、方法参数 随方法的调用创建,随方法执行结束自动释放 系统自动释放,无需手动管理
堆内存 对象的实际数据(属性值、实例成员) 随对象实例化创建,直到没有引用指向时被回收 由垃圾回收机制(GC)自动管理,大部分语言无需手动释放
通用垃圾回收核心思想
  1. 引用计数法 :给每个对象维护一个引用计数器,有一个引用指向它,计数器 + 1;引用失效,计数器 - 1;计数器为 0 时,标记为可回收。
    • 缺点:无法解决循环引用的问题(A 引用 B,B 引用 A,计数器永远不为 0)。
  2. 可达性分析算法:以「GC Root」(栈中的引用、静态变量引用等)为起点,向下搜索,形成引用链;如果一个对象不在任何引用链上,就标记为可回收,解决了循环引用的问题,是主流语言的通用实现。
内存泄漏的通用原因与规避方案
  • 内存泄漏的本质:长生命周期的对象,持有了短生命周期对象的引用,导致短生命周期对象用完后无法被 GC 回收,一直占用堆内存,最终导致内存溢出。
  • 通用常见原因:
    1. 静态集合类(比如静态 List、Map)持有对象引用,用完后没有移除;
    2. 资源对象(文件流、数据库连接、网络连接)用完后没有关闭;
    3. 监听器、回调函数注册后,没有在对象销毁时注销;
  • 规避方案:
    1. 尽量避免用静态集合存储对象,用完及时清空集合;
    2. 所有资源对象,必须在 finally 块中关闭释放;
    3. 注册的监听器、回调,必须在对象生命周期结束时注销。

第五部分 OOP 通用设计原则

写高质量 OOP 代码的通用准则,完全跨语言,不受语法限制,是从「会写 OOP 代码」到「写好 OOP 代码」的核心门槛。

5.1 OOP 底层核心原则

1. 高内聚、低耦合

OOP 设计的第一准则,所有其他原则都为这个准则服务。

  • 高内聚 :一个类只负责相关的一组功能,只有一个发生变化的原因,职责单一,把相关的代码放在一起,不相关的代码拆分出去。
    • 通俗类比:一个班级里,班长只负责管纪律,学习委员只负责管学习,生活委员只负责管后勤,每个人只干自己的事,职责清晰,这就是高内聚。
  • 低耦合 :类与类之间的依赖尽可能少,仅通过公开接口交互,一个类的内部修改,不影响其他依赖它的类。
    • 通俗类比:你去超市买东西,只需要和收银员对接,不用和仓库管理员、进货员、厂家对接,互相之间的依赖极少,这就是低耦合。
2. DRY 原则

Don't Repeat Yourself,不要重复你自己,杜绝重复代码,任何重复的逻辑,都必须封装复用。

  • 核心逻辑:重复的代码会导致维护成本极高,修改一处就要改所有重复的地方,极易出现 bug。
  • 通俗类比:你写了三遍计算圆面积的代码,一定要把它封装成一个方法,以后要改计算逻辑,只需要改这一个方法就行。
3. 开闭原则(OCP)

对扩展开放,对修改关闭,通过扩展实现新功能,而非修改原有代码,是 OOP 设计的终极目标。

  • 核心逻辑:原有代码是经过测试的稳定代码,修改原有代码极易引入新的 bug,通过扩展新增功能,不影响原有逻辑,保证系统的稳定性。
  • 通俗类比:你做了一个支付系统,原来支持微信支付,现在要加支付宝支付,不用改原来微信支付的代码,只要新增一个支付宝支付的类就行,这就是开闭原则。

5.2 SOLID 五大设计原则(OOP 核心)

原则名称 英文缩写 核心定义 通俗理解 新手避坑
单一职责原则 SRP 一个类应该只有一个发生变化的原因,即一个类仅承担一个职责 一个类只干一件事,不要让一个类既管用户登录,又管订单处理 不要写「上帝类」,一个类上万行代码,什么都干
开闭原则 OCP 对扩展开放,对修改关闭,用抽象构建框架,用实现扩展细节 新增功能不修改老代码,只加新代码,保证老代码的稳定性 不要硬编码业务逻辑,要通过抽象预留扩展点
里氏替换原则 LSP 所有引用父类的地方,必须能透明地使用其子类对象,子类不能破坏父类的原有业务逻辑 父类能用的地方,子类一定能用,子类不能改了父类的方法,导致原来的逻辑报错 不要重写父类的方法时,改变了父类的行为约定,比如父类的飞方法能飞,子类重写后抛出异常
接口隔离原则 ISP 不强制类实现它不需要的接口,应拆分粗粒度接口为多个细粒度的专用接口 不要给一个类塞一堆它用不到的方法,接口要小而专,不要大而全 不要写一个「万能接口」,里面有几十个方法,实现类只能空实现大部分方法
依赖倒置原则 DIP 高层模块不依赖低层模块,二者都依赖抽象;抽象不依赖具体实现,具体实现依赖抽象 面向接口编程,不是面向实现编程,上层代码只依赖接口,不依赖具体的实现类 不要在代码里直接 new 具体的实现类,要依赖接口,换实现的时候不用改上层代码

5.3 其他通用设计原则

1. 合成复用原则(CRP)

优先使用对象组合 / 聚合,而非继承来实现代码复用,是解决继承滥用的核心原则。

  • 核心逻辑:继承是强耦合,父类的修改会直接影响子类;组合是弱耦合,类之间仅通过接口交互,灵活性极高。
  • 通俗类比:你需要用手机的功能,不要让自己继承手机,而是拿着手机用(组合),手机坏了可以随时换,不影响你自己。
2. 迪米特法则(LoD / 最少知识原则)

一个对象对其他对象的了解应该越少越好,仅与直接的朋友通信,不要和陌生的对象直接交互。

  • 核心逻辑:减少类之间的依赖,降低耦合度,一个类只知道它直接依赖的类的信息,不知道其他类的内部细节。
  • 通俗类比:你去超市买东西,只需要和收银员对接,不用直接和仓库管理员说话,收银员会和仓库管理员对接,你不需要知道仓库的细节。

第六部分 OOP 通用工程实践与应用

6.1 OOP 类设计的通用步骤(需求→代码)

以「学生选课管理系统」为例,讲解从需求到代码的完整类设计流程,全场景通用:

  1. 需求分析 :从业务需求中提取核心实体、实体的属性、实体的行为
    • 核心实体:学生、课程、老师、班级
    • 学生属性:学号、姓名、年龄、班级;行为:选课、退课、查成绩
    • 课程属性:课程编号、课程名称、学分、授课老师;行为:添加学生、删除学生、统计选课人数
  2. 共性抽象 :提取多个实体的共性特征,抽象父类 / 接口,定义统一规范
    • 学生和老师都是系统用户,提取「用户」抽象父类,定义共性属性(id、姓名、密码)、共性行为(登录、修改密码)
    • 课程分为必修课、选修课,提取「课程」接口,定义选课、退课的统一规范
  3. 关系梳理 :设计类之间的继承、组合、依赖关系,优先用组合替代继承
    • 学生、老师 继承 用户(泛化关系)
    • 必修课、选修课 实现 课程接口(实现关系)
    • 学生 持有 课程列表(聚合关系,学生和课程生命周期独立)
    • 课程 持有 授课老师(关联关系)
  4. 封装设计 :定义每个类的访问权限,明确公开接口与内部实现
    • 所有核心属性私有化,提供 getter/setter,添加校验逻辑(比如学号不能修改,学分必须在 1-10 之间)
    • 仅对外暴露必须的业务方法,内部实现逻辑全部私有
  5. 扩展性设计 :基于开闭原则,预留扩展点,避免硬编码
    • 后续新增网课类型,只需要实现课程接口,原有代码无需修改
    • 后续新增管理员用户,只需要继承用户父类,原有登录逻辑完全复用
  6. 验证优化 :对照设计原则,校验类设计是否符合高内聚低耦合要求
    • 每个类是不是只有一个职责?
    • 类之间的耦合度是不是最低?
    • 是不是符合开闭原则?
    • 有没有滥用继承?

6.2 类间关系的通用分类(UML 标准)

类间关系的耦合度从强到弱排序,全 OOP 语言通用:

关系类型 核心定义 关系强度 通俗类比 代码表现
泛化关系 继承关系,代表「is-a」 强耦合 狗是动物,学生是人 子类继承父类
实现关系 类实现接口,代表「can-do」 中强耦合 飞机实现飞的接口,人实现游泳的接口 类 implements 接口
组合关系 整体与部分,生命周期完全一致,代表「contains-a」 强耦合 人和心脏,人没了,心脏也没了;订单和订单项,订单删了,订单项也删了 类的成员变量是另一个类的对象,在构造方法中创建
聚合关系 整体与部分,生命周期相互独立,代表「has-a」 中耦合 班级和学生,班级解散了,学生还在;汽车和轮子,汽车报废了,轮子还能拆下来用 类的成员变量是另一个类的对象,通过构造方法 /setter 传入
关联关系 类之间的稳定引用关系 弱耦合 学生和学号,老师和课程 类的成员变量是另一个类的对象
依赖关系 类之间的临时使用关系,代表「use-a」 极弱耦合 学生的选课方法里,临时用到了课程对象;方法的参数、局部变量是另一个类 方法的参数、局部变量、返回值是另一个类

6.3 OOP 通用经典设计模式

设计模式是 OOP 设计原则的经典落地实现,是前辈们总结的、解决特定业务场景痛点的最佳实践,完全跨语言通用,分为三大类:

6.4 OOP 工程化通用实践

  1. 异常处理的 OOP 设计:基于业务场景自定义异常类,继承自语言的基础异常类,构建层级化的异常体系,比如用户异常、订单异常、支付异常,精准定位业务问题。
  2. OOP 代码的单元测试:基于类的行为设计测试用例,面向接口测试,一个类对应一个测试类,一个方法对应多个测试用例,保证每个类的行为符合预期。
  3. 通用代码规范
    • 命名规范:类名用大驼峰(Student、Order),方法名、属性名用小驼峰(study、orderId),常量全大写(SCHOOL_NAME);
    • 文件规范:一个类一个文件,文件名和类名完全一致;
    • 行数规范:一个类的代码行数建议不超过 500 行,一个方法的代码行数建议不超过 50 行,超出就需要拆分。
  4. 面向对象的项目分层设计 :企业级项目通用的分层架构,每层职责单一,仅通过接口交互,极致降低耦合:
    • 实体层(Entity/Model):封装业务实体,对应数据库表结构;
    • DAO 层(数据访问层):负责和数据库交互,封装增删改查逻辑;
    • 服务层(Service):封装核心业务逻辑,调用 DAO 层,对外提供业务接口;
    • 控制层(Controller):负责和前端 / 客户端交互,接收请求,调用 Service 层,返回响应结果。

第七部分 OOP 常见误区与避坑指南

7.1 设计层面通用误区

  1. 滥用继承:为了单纯复用代码强行使用继承,没有「is-a」的关系,导致类层级爆炸、耦合度过高,后续修改父类会影响所有子类,维护成本极高。
  2. 过度封装:无意义的 getter/setter,每个属性都无脑生成 get/set,没有任何校验逻辑;过度拆分类,把一个简单的逻辑拆成十几个类,导致代码冗余、可读性极差。
  3. 封装不足:核心属性全公开,内部实现完全暴露,外部代码可以随意修改对象的属性,导致数据不可控、出现 bug 无法定位,维护成本极高。
  4. 大而全的上帝类:一个类承担数十个职责,代码上万行,什么都干,违背单一职责原则,一个小修改就可能影响整个类的逻辑,完全无法维护、无法测试。
  5. 滥用静态成员:把本该实例化的业务逻辑写成静态工具类,导致代码无法扩展、无法重写、无法测试,变成了面向过程的代码,完全失去了 OOP 的优势。
  6. 面向实现编程:代码里全是具体的实现类,没有抽象、没有接口,上层代码直接依赖底层实现,换一个实现就要改大量的上层代码,扩展性极差,完全违背开闭原则。

7.2 代码实现通用易错点

  1. 混淆方法重载与重写,重写时写错方法名 / 参数列表,导致多态逻辑完全失效。
  2. 在构造方法中调用可重写的方法:父类构造方法执行时,子类的属性还未初始化,子类重写的方法如果用到了子类的属性,会导致空指针异常、数据异常。
  3. 子类重写父类方法时,违背里氏替换原则,改变了父类的行为约定,导致父类能用的地方,子类用了就报错。
  4. 多继承场景下,忽略菱形继承问题,导致方法调用逻辑混乱,出现非预期的 bug。
  5. 忽略对象生命周期,在循环里频繁创建短生命周期对象,导致 GC 频繁执行,程序性能严重下降;长生命周期对象持有短生命周期对象的引用,导致内存泄漏。

第八部分 补充:主流 OOP 语言语法差异对照(图/表)

通用核心概念 Java Python C++ C# JavaScript(ES6+)
类定义 public class 类名 {} class 类名: class 类名 {}; public class 类名 {} class 类名 {}
构造方法 类名 () {} def __init__(self): 类名 () {} 类名 () {} constructor() {}
析构方法 由 GC 自动管理,重写 finalize ()(不推荐) def __del__(self): ~ 类名 () {} 析构函数~类名 () {}、IDisposable 接口 由 GC 自动管理
this/self this self(必须作为方法第一个参数) this this this
继承 class 子类 extends 父类 {} class 子类(父类1, 父类2): class 子类 : 访问权限 父类 {} class 子类 : 父类 {} class 子类 extends 父类 {}
公开级别 public 无关键字,默认公开 public: public 无关键字,默认公开
受保护级别 protected 单下划线_xxx(约定俗成) protected: protected ES2022+ #xxx(私有),无原生 protected
私有级别 private 双下划线__xxx(名称改写) private: private ES2022+ #xxx
抽象类 abstract class 类名 {} 通过 abc 模块的 ABC、abstractmethod 实现 包含纯虚函数的类 abstract class 类名 {} 无原生抽象类,通过 throw new Error 模拟
接口 interface 接口名 {} 无原生接口,通过抽象类 / 鸭子类型实现 无原生接口,通过纯虚函数类实现 interface 接口名 {} 无原生接口,通过 TypeScript 支持
方法重写 子类方法加@Override注解 子类定义同名同参数方法即可 子类定义同名同参数方法,加override关键字(C++11+) 子类方法加override关键字 子类定义同名同参数方法即可
静态成员 static关键字修饰 @staticmethod@classmethod装饰器 static关键字修饰 static关键字修饰 static关键字修饰

第九部分 附录

9.1 OOP 核心术语中英对照表

中文术语 英文术语 核心缩写
面向对象编程 Object-Oriented Programming OOP
面向过程编程 Procedure-Oriented Programming POP
Class -
对象 / 实例 Object/Instance -
属性 Attribute/Field -
方法 Method/Function -
构造方法 Constructor -
析构方法 Destructor -
封装 Encapsulation -
继承 Inheritance -
多态 Polymorphism -
抽象 Abstraction -
抽象类 Abstract Class -
接口 Interface -
重载 Overload -
重写 / 覆盖 Override -
开闭原则 Open-Closed Principle OCP
单一职责原则 Single Responsibility Principle SRP
里氏替换原则 Liskov Substitution Principle LSP
接口隔离原则 Interface Segregation Principle ISP
依赖倒置原则 Dependency Inversion Principle DIP

9.2 OOP 通用入门练习案例(跨语言可实现)

图书管理系统,覆盖 OOP 所有核心知识点:

  1. 核心实体:图书、用户(管理员、普通读者)、借阅记录
  2. 核心要求:
    • 抽象用户父类,管理员和读者继承用户类,实现不同的权限;
    • 封装图书的核心属性,禁止外部直接修改库存;
    • 实现多态:不同用户的借书、还书行为有不同的规则(管理员可借无限本,读者最多借 5 本);
    • 实现借阅记录的新增、查询、统计功能;
    • 符合高内聚低耦合、开闭原则。

9.3 OOP 进阶实战项目设计思路

  1. 电商订单系统:覆盖类设计、分层架构、设计模式(工厂模式、策略模式、状态模式)、异常体系、单元测试;
  2. 简易 2D 游戏引擎:覆盖继承、多态、组合、组件化设计、对象生命周期管理;
  3. 通用权限管理系统:覆盖抽象、接口、多态、开闭原则、扩展性设计。
相关推荐
AI-小柒2 小时前
大模型API中转推荐:Dataeyes API 600+模型统一网关与负载均衡部署,claude编程、香蕉生图、视频大模型聚合平台
大数据·运维·开发语言·人工智能·算法·机器学习·负载均衡
Shepherdppz2 小时前
【避坑指南】超级笔记 Supernote 私有云部署完整指南:从零到一在群晖Synology NAS上搭建私人同步服务器
运维·服务器·笔记
猹叉叉(学习版)2 小时前
【系统分析师_知识点整理】 13.软件实现与测试
软件测试·笔记·软考·系统分析师
E_ICEBLUE2 小时前
在 Python 中给 PDF 设置背景图或背景色
开发语言·python·pdf
小陈phd2 小时前
多模态大模型学习笔记(二十九)—— 生成对抗网络(GAN)从原理到实战:实现第一个生成模型
笔记·学习·生成对抗网络
ling__i2 小时前
接口测试常见问题
开发语言·lua
Heartache boy2 小时前
野火STM32_HAL库版课程笔记-TB6612FNG驱动有刷电机
笔记·stm32·单片机
iiiiii112 小时前
【理论推导】指数族分布的核心性质:对数配分函数的梯度为什么是充分统计量的期望?
人工智能·笔记·深度学习·数学·机器学习·概率论·指数族分布
daxi1502 小时前
C语言从入门到进阶——第18讲:内存函数
c语言·开发语言·算法