七、面向对象

78 阅读8分钟

1 类和对象

1.1 面向对象的介绍

1.1.1 面向过程

是一种以 过程函数 为中心的编程范式,它强调的是 解决问题的步骤。程序被分解为一系列函数或过程的集合,每个函数负责完成一个特定的任务,数据和操作数据的函数是分离的。面向过程编程的核心在于 如何通过一系列步骤来达到目标

类比: 像做菜,按照菜谱一步步操作,每个步骤是独立的(切菜、炒菜、调味),但需要自己管理材料和工具。

适用场景: 适合解决简单、线性流程的问题,代码结构清晰,但扩展性和复用性较差。

示例: 实现计算器程序,下面是面向过程的代码。

def add(a, b):
    return a + b
 
def subtract(a, b):
    return a - b
 
def multiply(a, b):
    return a * b
 
def divide(a, b):
    if b == 0:
        raise ValueError("Division by zero")
    return a / b
 
# 使用函数
result = add(5, 3)
print(result)  # 输出 8

1.1.2 面向对象

面向对象是一种以 对象 为中心的编程范式,它强调的是 数据和操作数据的方法的封装。程序被组织为一系列对象的集合,每个对象包含数据(属性)和操作这些数据的方法(行为)。面向对象编程的核心在于 如何通过对象之间的交互来解决问题

类比: 像点外卖,你只需要告诉商家(对象)你要什么菜,商家会处理所有细节(切菜、炒菜、调味),你只需要等待结果。

适用场景: 适合解决复杂问题,通过封装、继承和多态等特性提高代码的复用性和扩展性,更符合人类的思维方式。

示例: 实现计算器程序,下面是面向对象的代码。

class Calculator:
    def add(self, a, b):
        return a + b
 
    def subtract(self, a, b):
        return a - b
 
    def multiply(self, a, b):
        return a * b
 
    def divide(self, a, b):
        if b == 0:
            raise ValueError("Division by zero")
        return a / b
 
# 使用对象
calc = Calculator()
result = calc.add(5, 3)
print(result)  # 输出 8

1.2 类和对象的介绍

1.2.1 类

之前我们学习接触到的类,主要是测试类(带 main 方法的类),其主要是用来运行代码。

接下来学习的是 实体类,它主要是一类事物的抽象表示形式,比如:人类、动物类、手机类等。下面会举例说明。

类的组成部分

类的组成部分主要分为两种:属性(成员变量)行为(成员方法)

  • 属性(成员变量),用于描述类对象的状态的数据
    • 定义位置:定义在类中的方法外面
    • 作用范围:作用于当前类
    • 定义格式:数据类型 变量名
    • 定义的时候,可以不用初始化赋值,会有默认值:
      • 整数:0
      • 小数:0.0
      • 字符:'\u0000'
      • 布尔:false
      • 引用:null
  • 行为(成员方法),用于描述对象可以执行的操作或功能。
示例

以下几个类都属于同个包。

public class Person {
    String name;
    int age;

    public void eat() {
        System.out.println("干饭");
    }

    public void drink() {
        System.out.println("喝饮料");
    }
}
public class Phone {
    String brand;

    public void call(){
        System.out.println("打电话");
    }
}
public class Animal {
    String kind;
    int num;

    public void statistics(){
        System.out.println("统计动物数量:" + num);
    }
}
public class Demo01 {
    public static void main(String[] args) {
        Person person = new Person();
        person.eat();
        Phone phone = new Phone();
        phone.call();
        Animal animal = new Animal();
        animal.num = 100;
        animal.statistics();
    }
}

注意: 在同个包下的类可以直接使用,而无需导包。

1.2.2 对象

概述:一类事物的具体体现。

使用:

  • 导包:import 包名.类名
  • 创建对象,想要使用哪个类中的成员,就 new 哪个类
  • 调用成员(成员变量、成员方法),通过 new 出来的对象就可以使用构造出该对象的类里面变量和方法。
package com.testing.oop.Demo02;

public class Phone {
    String brand;
    String color;
    int price;

    public void call(String name) {
        String callStr1 = "价格为" + price + "的" + color + brand;
        String callStr2 = "给" + name + "打电话";
        System.out.println(callStr1 + callStr2);
    }

    public String message(String name) {
        return "给" + name + "发短信";
    }
}
package com.testing.oop.Demo02;

public class Demo02 {
    public static void main(String[] args) {
        Phone phone = new Phone();
        phone.brand = "HUAWEI";
        phone.color = "黑色";
        phone.price = 5220;

        phone.call("王思聪");
        String sms = phone.message("柳岩");
        System.out.println(sms);
    }
}

/*
价格为5220的黑色HUAWEI给王思聪打电话
给柳岩发短信
*/

1.3 匿名对象的使用

匿名对象是指创建对象(new一个对象)时,不将对象赋值给任何变量,而直接使用对象。

匿名对象的使用时机:当只需要调用一个对象的方法,且不涉及变量的赋值时,可以使用匿名对象。

package com.testing.oop.Demo03;

public class Person {
    String name = "";

    public void eat() {
        if (name.isEmpty()) {
            System.out.println("人要吃饭!");
        } else {
            System.out.println(name + "要吃饭!");
        }
    }
}
package com.testing.oop.Demo03;

public class Demo03 {
    public static void main(String[] args) {
        Person person = new Person();
        person.name = "姚明";
        person.eat();

        new Person().eat();
    }
}

/*
姚明要吃饭!
人要吃饭!
*/

1.4 对象的内存图

1.4.1 一个对象的内存图

image.png

1.4.2 两个对象的内存图

image.png

同个 class new 出来两个不同的对象,在内存堆中是各自管理自己的成员变量的,彼此之间互不影响。

1.4.3 两个对象指向同一片堆空间的内存图

image.png

两个变量指向同个实例对象,当改变其中一个变量(存储着对象地址)的某个成员变量时,另外一个变量(存储着同个对象地址)也会被同步修改。

1.5 成员变量和局部变量的区别

示例代码:

public class Person {
    // 成员变量定义在类内,方法的外面,作用于当前类
    String name; // 没有初始化赋值,引用类型默认是 null
    int age; // 没有初始化赋值,int 类型默认是 0

    public void eat() {
        // 局部变量定义方法的代码块内,作用于当前代码块
        // String food;
        // System.out.println(food); // 未初始化赋值就使用 food,会报错:"变量 'food' 可能尚未初始化"
        System.out.println("干饭");
    }

    public void drink(String thing) {
        // 或者局部变量定义在方法的参数上,作用于当前代码块
        System.out.println("喝饮料" + thing);
    }
}

主要有以下区别:

序号区别点成员变量局部变量
1定义位置定义在类中方法的外面定义在方法体内,或者方法参数中
2初始化值初始化后有默认值,不用手动赋值也可直接使用初始化后没有默认值,必须手动赋值才能使用,否则报错
3作用范围作用于整个 class作用于当前方法体内其所在的代码块
4生命周期随着对象的创建而产生,消失而消失随着方法的调用而产生,调用完毕而消失
5内存位置在内存堆中,跟着实例对象位置走在内存栈中,跟着方法走

1.6 练习

定义一个 MyDate 类,要求成员变量有:year、month、day,再定义一个 Citizen 类,要求成员变量有:name、birthday、idCard,为这三个成员变量赋值,并取值打印。

// /Demo04/MyDate.java
public class MyDate {
    String year;
    String month;
    String day;
}
// /Demo04/Citizen.java
public class Citizen {
    String name;
    MyDate birthday = new MyDate();
    String idCard;
}
// /Demo04/Citizen.java
public class Demo04 {
    public static void main(String[] args) {
        Citizen citizen = new Citizen();
        citizen.name = "江哥";
        citizen.birthday.year = "2025";
        citizen.birthday.month = "07";
        citizen.birthday.day = "07";
        citizen.idCard = "auth123";

        System.out.println(citizen.name + "_" + citizen.birthday.year + citizen.birthday.month + citizen.birthday.day + "_" + citizen.idCard);
    }
}

/*
江哥_20250707_auth123
*/

2 封装

封装的本质是 信息隐藏接口暴露。通过将对象的内部状态(属性)和行为(方法)绑定成一个整体,并对外部隐藏实现细节,仅通过公共接口与外界交互。

这种设计模式有利于:

  • 保护数据安全:防止外部直接修改对象的内部状态(如通过 private 修饰属性)
  • 降低耦合度:外部代码只需依赖接口,无需关心内部实现,从而提高代码的可维护性和扩展性
  • 模块化设计:将功能封装为独立的单元,便于复用和测试

样例 1

package com.testing.oop.Demo05;

import java.util.Arrays;

public class Demo05Test01 {
    public static void main(String[] args) {
        int[] arr = {1, 2, 3, 4};

        // 这里的 toString 就是一个封装好的功能,通过外界的参数来与其进行交互
        System.out.println(Arrays.toString(arr));
    }
}

/*
[1, 2, 3, 4]
*/

样例 2

package com.testing.oop.Demo05;

public class Demo05Test02 {
    public static void main(String[] args) {
        int[] arr = {11, 22, 33, 44};
        String res = customToString(arr);
        System.out.println(res);
    }

    // 封装自定义 toString 功能
    public static String customToString(int[] arr) {
        StringBuilder sb = new StringBuilder();
        sb.append("[");
        for (int i = 0; i < arr.length; i++) {
            if (i > 0) {
                sb.append(',');
            }
            sb.append(arr[i]);
        }
        sb.append("]");

        return sb.toString();
    }
}

/*
[11,22,33,44]
*/

样例 3

以下 2 个类都属于同个包。

package com.testing.oop.Demo05;

public class Demo05Test03 {
    public static void main(String[] args) {
        Person p = new Person();
        System.out.println("没有 set name & age 之前,Name==" + p.getName() + ",Age==" + p.getAge() );
        p.setName("鸣人");
        p.setAge(20);
        System.out.println("set name & age 之后,Name==" + p.getName() + ",Age==" + p.getAge() );
    }
}

/*
没有 set name & age 之前,Name==null,Age==0
set name & age 之后,Name==鸣人,Age==20
*/
package com.testing.oop.Demo05;

public class Person {
    private String name;
    private int age;

    public String getName() {
        return this.name;
    }

    public int getAge() {
        return this.age;
    }

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

    public void setAge(int age) {
        if (age < 0 || age > 150) {
            System.out.println("您是神仙!");
        } else {
            this.age = age;
        }
    }
}

2.1 关于 class 中的 this

在类中,this 指向 new 出的当前对象。例如:new 出来的一个对象,调用这个对象中的某个方法,方法中 this 的指向就是这个对象。

package com.testing.oop.Demo05;

public class Demo05Test04 {
    public static void main(String[] args) {
        Person p1 = new Person();
        System.out.println("对象1:" + p1);
        p1.findThis("p1"); // this 指向当前对象的地址值

        Person p2 = new Person();
        System.out.println("对象2:" + p2);
        p2.findThis("p2"); // this 指向当前对象的地址值
    }
}
package com.testing.oop.Demo05;

public class Person {
    public void findThis(String indicator) {
        System.out.println(indicator + ": " + this);
    }
}

3 static 关键字

4