Skip to content

面向对象编程

约 1775 字大约 6 分钟

2025-03-02

类与对象

重要

一个完整的类:

  1. 核心组成部分
    • 属性(实例变量-每个对象独立拥有的属性、静态变量-类级别共享)
    • 构造方法:初始化对象状态
    • 实例方法:定义对象的行为,可以访问实例变量和静态变量
    • 静态方法:定义类级别的行为,只能访问静态变量
    • Getter/Setter:控制字段的访问权限(封装性)
    • 访问修饰符(封装):控制类成员的可见性
  2. 面向对象特性
    • 继承(extends):复用代码,建立类层次关系
    • 多态(方法重写、父类引用子类对象)
    • 抽象类与接口
    • 内部类:逻辑分组,增强封装性
  3. 扩展内容
    • 枚举类型
    • 注解
    • 泛型
    • 单例模式
  • 类设计原则
    • 单一职责原则:一个类只负责一个功能领域
    • 开闭原则:对扩展开放,对修改封闭(通过继承/组合扩展)
    • 高内聚低耦合:类内部高度聚合,类之间依赖最小化
public class Person {
    // 实例变量(对象特有属性)
    private String name;
    private int age;

    // 静态变量(类级别共享)
    public static String species = "Human";

    // 构造方法(初始化对象)
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // 实例方法
    public void introduce() {
        System.out.println("Hi, I'm " + name + ", " + age + " years old.");
    }

    // 静态方法
    public static void displaySpecies() {
        System.out.println("Species: " + species);
    }

    // Getter & Setter(可选)
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    // 测试入口
    public static void main(String[] args) {
        // 创建对象(触发堆内存分配)
        Person alice = new Person("Alice", 30);
        alice.introduce();  // 输出: Hi, I'm Alice, 30 years old.

        // 访问静态变量
        System.out.println(Person.species);  // 输出: Human
        Person.displaySpecies();             // 输出: Species: Human

        // 修改静态变量(影响所有实例)
        Person.species = "Homo sapiens";
        System.out.println(Person.species);  // 输出: Homo sapiens
    }
}

类和对象的内存分配机制(对象创建的流程分析)

  • Java内存的结构分析
    • 栈区(Stack):存储 局部变量方法调用栈帧
    • 堆区(Heap):存储所有对象实例和数组
    • 方法区:类结构静态变量常量池JIT代码

提示

此处加配图:对象创建的流程分析 内存分配 方法调用过程等

在Java中,对象创建和内存分配涉及多个内存区域的协作,以创建一个Person类对象为例,分析内存结构的关键步骤如下:

  1. 类加载 方法区:

    • 加载类的字节码文件(.class文件)
    • 存储静态变量species,初始化值为"Human"
    • 存储方法代码(构造方法、introduce()displaySpecies()等方法的字节码)
    • 存储常量池(如字符串常量 "Hi, I'm "
  2. 对象实例化(堆内存)

    • 分配对象内存空间(包含对象头、实例变量name和age)
    • name字段指向堆中独立的String对象(存储 "Alice" 的字符数组)
    • age字段直接存储原始值30
  3. 栈内存与引用关联

    • main 方法的栈帧中存储局部变量 alice(保存堆中 Person 对象的内存地址)
    • 方法调用时(如 alice.introduce()),栈中压入新的栈帧(存储方法参数、局部变量等)
  4. 方法调用 栈帧管理方法调用过程中的参数传递和局部变量

  5. 静态变量访问 直接读写方法区中的静态变量species(无需对象实例)

成员方法的传参机制

  • 基本数据类型:传递的是值(值拷贝),形参的改变不影响实参
  • 引用数据类型:传递的是地址(传递的也是值,但是值是地址),可以通过形参影响实参

方法重载(Overload)

  • 方法名:必须相同
  • 形参列表:形参类型或个数或顺序,至少有一样不同,参数名无要求
  • 返回类型:无要求

访问修饰符

访问级别访问控制修饰符类同类同包子类不同包
公开public
受保护protected
默认无修饰符
私有private

面向对象编程

封装继承多态

封装

封装:把抽象出的数据【属性】和对数据的操作【方法】封装在一起,数据被保护在内部,程序的其他部分只有通过被授权的操作【方法】,才能对数据进行操作。

封装的步骤:

  • 将属性私有化private
  • 提供公共的public set方法,用于对属性判断并赋值
  • 提供公共的public get方法,用于获取属性的值

继承

继承:当多个类之间存在相同的属性和方法时,可以从这些类中抽象出符类,在父类中定义这些相同的属性和方法,子类通过extends来声明继承父类即可拥有父类定义的属性和方法,从而建立类之间的层级关系,实现代码复用和逻辑扩展。

提示

添加继承的本质分析

继承的内存布局

super和this关键字的对比

区别点thissuper
访问
属性
访问本类中的属性,如果本类没有此属性,则从父类继续查找从父类开始查找属性
调用
方法
访问本类中的方法,如果本类没有此方法,则从父类继续查找从父类开始查找方法
调用
构造器
调用本类构造器,必须放在构造器的首行调用父类构造器,必须放在子类构造器的首行
特殊表示当前对象子类中访问父类对象

方法重写(Override)

方法重写:子类重写父类的方法,子类中的某个方法和父类中某个方法的名称、返回类型、形参列表都一样。

多态

多态的前提是,两个对象(类)存在继承关系

重要

  • 一个对象的编译类型和运行类型可以不一致
  • 编译类型在定义对象时,就确定了,不能改变
  • 运行类型是可以变化的
  • 编译类型看定义时=号的左边,运行类型看=号的右边

多态的向上转型

  • 父类引用指向子类对象
  • 语法:父类类型 引用名=new 子类类型();
  • 特点:编译类型看左边,运行类型看右边。
    • 可以调用父类中的所有成员(需遵守访问权限)
    • 不能调用子类中特有成员
    • 最终运行效果看子类的具体实现

多态的向下转型

  • 语法:子类类型引用名=(子类类型)父类引用
  • 只能强转父类的引用,不能强转父类的对象
  • 要求父类的引用必须指向的是当前目标类型的对象
  • 当向下转型后,可以调用子类类型中所有的成员

Java的动态绑定机制

重要

  1. 当调用对象方法的时候,该方法会和该对象的内存地址/运行类型绑定
  2. 当调用对象属性的时候,没有动态绑定机制,哪里声明,哪里使用