20260720-笔记.md 22 KB

JavaSE 基础 — Day06 笔记

日期:2026-07-20
项目c260720
作者:WanJL


一、面向对象基础(Object-Oriented Programming)

1. 面向对象思想概述

对比维度 面向对象(Java) 面向过程(C)
思想核心 以对象为中心,通过指挥对象实现操作 以过程为中心,功能都由自己实现
特点 更符合人类思维习惯,易于维护和扩展 按步骤一步步执行,代码直接
关键词 类、对象、封装、继承、多态 函数、过程、步骤

Java 中一切皆为对象,是一种以对象为中心的编程思想。

2. 类(Class)与对象(Object)的关系

类比:设计图纸(类)与成品(对象)的关系。

  • 1 套设计图纸 → 可以做出 多个成品
  • 1 个类 → 可以创建 多个对象
  • 是模板、蓝图、设计图纸、规则、要求,描述一个对象的所有属性和操作
  • 对象 是能够看得到摸得着的真实存在的实体

类的定义: 类是现实生活中一类具有相同属性和行为的事物的抽象。

3. 类的定义格式

修饰符 class 类名 {
    数据类型 属性名;          // 成员变量(属性)

    修饰符 返回值类型 方法名(){  // 成员方法(行为)

    }
}

类的成员组成

成员 对应概念 表现形式
属性(Property) 事物特征 成员变量(类中方法外的变量)
行为(Behavior) 事物操作 成员方法(去掉 static 关键字的方法)

4. 创建对象与使用成员

创建对象格式

类名 对象名 = new 类名();

调用成员格式

对象名.成员变量;     // 访问属性
对象名.成员方法();   // 调用方法

5. 成员变量(Member Variable)与局部变量(Local Variable)区别

文件Demo03.java

对比维度 成员变量 局部变量
类中位置 定义在【类内部,方法外部】 定义在【方法内部】(方法的参数也属于局部变量)
内存位置 堆内存(Heap)中 栈内存(Stack)中
生命周期 随着对象的存在而存在,随着对象的消失而消失 随着方法的调用而存在,随着方法的调用结束而消失
初始化值 有默认初始化值(整数→0,引用类型→null 没有默认初始化值,必须先定义赋值才能使用
public class Student {
    String name;  // 成员变量 —— 在类内部、方法外部
    int age;      // 成员变量

    public void study() {
        String msg = "学习中";  // 局部变量 —— 在方法内部
        System.out.println(msg);
    }
}

6. 对象引用与内存共享

文件Demo03.java

当多个引用变量指向 同一个内存地址 时,它们操作的是同一块内存空间。任何一个引用修改了数据,其他引用获取到的都是修改后的数据。

public class Demo03 {
    public static void main(String[] args) {
        Teacher t1 = new Teacher();  // t1 引用指向 0x1024
        t1.name = "张三";
        t1.sleep();                  // 输出:张三在休息....

        Teacher t2 = t1;             // t2 也指向 0x1024(与 t1 同一对象)
        t2.name = "李四";
        t2.id = "1001";
        t1.sleep();                  // 输出:1001李四在休息....(已被 t2 修改)
    }
}

图解t1t2 是两个不同的引用变量,但存储的是同一个对象的地址 0x1024。通过 t2.name = "李四" 修改后,t1.name 也变成"李四",因为它们是同一块内存。


7. 对象数组(Object Array)

文件Test01.java, Test02.java

对象数组的数组元素类型是类名,存储的是对象的引用地址(而非对象本身)。

// 定义一个可以存储 10 个 BaiLu 对象引用的数组
BaiLu[] bailus = new BaiLu[10];
// 定义一个可以存储 10 个 Bike 对象引用的数组
Bike[] bikes = new Bike[10];

创建对象并存入数组的标准操作

// 1. 先创建对象
BaiLu b = new BaiLu();
// 2. 调用对象方法
b.up("青天");
// 3. 将对象引用(地址值)存入数组
bailus[i] = b;

对比基本类型数组int[] arr = new int[10] 存的是数值;对象数组存的是引用(地址)。


8. 封装(Encapsulation)

文件Demo04.java, Person.java, PersonTest.java

8.1 面向对象三大特性

Java 面向对象有三大特性,本质上都是为了 减少写代码、让代码能够复用

特性 说明
封装 把该隐藏的隐藏起来,把该显示的显示出来
继承 子类自动拥有父类的成员,实现代码复用
多态 同一行为在不同对象上产生不同效果

8.2 为什么要封装

问题场景:如果类的属性直接暴露,可以随意赋值,可能导致不符合业务逻辑的数据。

Person p = new Person();
p.age = 250;      // 语法正确,但业务上不合理(人的年龄不可能250岁)
p.age = -250000;  // 同样不合理

解决方案(封装两步走)

第一步:把属性的权限提高,让【本类以外】都无法直接访问(赋值、取值)
       → 使用 private 关键字

第二步:定义公开(public)的方法来赋值和取值
       → setXxx() 方法:赋值,内部做合法性判断
       → getXxx() 方法:取值

8.3 访问权限修饰符

修饰符 含义 访问范围
public 公开的 任何地方的任何类都能访问
private 私有的 除了自身所在的类之外,任何类都不能访问
default(默认) 默认的 本类中、同包中可以访问(不写任何修饰符)
protected 受保护的 本类中、同包中可以访问,非同包的子类可以访问(讲继承时再细说)

8.4 封装的标准实现 —— setter/getter

public class Person {
    String name;
    private int age;  // 私有化:本类以外无法直接访问

    // 公开的赋值方法(setter)—— 带合法性校验
    public void setAge(int newAge) {
        if (newAge >= 1 && newAge < 130) {
            age = newAge;
        } else {
            System.out.println("年龄超过规定限制,赋值无效...");
        }
    }

    // 公开的取值方法(getter)
    public int getAge() {
        return age;
    }
}

8.5 测试封装效果

public class PersonTest {
    public static void main(String[] args) {
        Person p = new Person();
        p.name = "张三";
        p.setAge(200);          // 赋值无效:年龄超过限制
        int age = p.getAge();   // 获取到的 age 是默认值 0
        System.out.println(age); // 输出:0
    }
}

封装的核心思想:隐藏功能的实现细节,仅暴露功能的调用方式。就像 USB 接口,用户只需插拔,不需关心内部电路。

8.6 this 关键字

文件Product.java

当方法参数(局部变量)与成员变量同名时,按照就近原则,方法内部默认使用的是局部变量。此时需要用 this 关键字来区分。

public class Product {
    private String brand;   // 成员变量

    // 参数 brand 与成员变量 brand 同名
    public void setBrand(String brand) {
        // this.brand 是成员变量,brand 是局部变量(方法参数)
        this.brand = brand;
    }
}

this 的含义:当前对象的引用。this.成员变量 调用的一定是当前对象的成员变量,this.成员方法() 调用的一定是当前对象的成员方法。

使用 this 的标准 getter/setter 写法

public void setName(String name) {
    this.name = name;       // this 区分成员变量和参数
}
public String getName() {
    return this.name;       // 此处可以省略 this(无同名冲突),但加上更清晰
}

8.7 封装的原则与好处

封装的原则

  • 类的某些属性信息隐藏在类的内部,不允许外部程序直接访问
  • 通过该类提供的 公有方法 来实现对隐藏信息的操作和访问
  • 成员变量使用 private 修饰,成员方法使用 public 修饰

封装的好处

  1. 安全性:通过方法控制成员变量的操作,可增加校验逻辑,防止非法数据
  2. 复用性:把代码用方法封装起来,可以重复调用
  3. 隐藏细节:使用者只需调用方法,不需要了解内部实现

二、代码实战:类与对象完整示例

1. Student 学生类

文件Demo02.java / Student.java

定义类(Student.java)

public class Student {
    String name;   // 成员变量:姓名
    int age;       // 成员变量:年龄

    // 成员方法:学习
    public void study() {
        System.out.println("姓名:" + name + ",年龄:" + age + ",在学习");
    }
}

使用对象(Demo02.java)

public class Demo02 {
    public static void main(String[] args) {
        // 创建第一个学生对象
        Student s = new Student();
        s.name = "张三";
        s.age = 25;
        s.study();

        // 创建第二个学生对象
        Student s1 = new Student();
        s1.name = "李四";
        s1.age = 20;
        s1.study();
    }
}

要点:同一个 Student 类可以创建多个对象,每个对象拥有自己独立的属性值。


2. Dog 狗类

文件Dog.java

public class Dog {
    double weight;  // 成员变量:体重
    double height;  // 成员变量:身高

    public static void main(String[] args) {
        Dog d = new Dog();
        d.height = 15.6;
        d.weight = 3.14;
    }
}

3. Teacher 教师类 + TeacherTest 测试类

文件Teacher.java / TeacherTest.java

定义类(Teacher.java)

public class Teacher {
    String id;      // 教工号
    String name;    // 姓名
    int age;        // 年龄

    public void teaching() {
        System.out.println(id + name + age + "在授课....");
    }

    public void sleep() {
        System.out.println(id + name + age + "在休息....");
    }
}

测试类(TeacherTest.java)—— 重点:对象地址输出

public class TeacherTest {
    public static void main(String[] args) {
        Teacher t = new Teacher();
        t.id = "1001";
        t.name = "张三";
        t.age = 25;
        t.teaching();
        t.sleep();

        // 直接输出对象名 —— 得到内存地址
        System.out.println(t);
        // 输出示例:Teacher@4769b07b
    }
}

对象地址输出解析

直接打印对象名时,输出格式为:类型@哈希码

部分 含义
Teacher 对象所属的类型
@ 分隔符
4769b07b 对象在内存中的地址(哈希码的十六进制表示)

4. 对象数组实战①——黄鹂与白鹭(古诗场景)

文件HuangLi.java, BaiLu.java, Test01.java

定义类——黄鹂(HuangLi.java)

public class HuangLi {
    public void sing(String s) {
        System.out.println("黄鹂鸣" + s);
    }
}

定义类——白鹭(BaiLu.java)

public class BaiLu {
    public void up(String s) {
        System.out.println("白鹭上" + s);
    }
}

测试类 —— 使用对象数组

public class Test01 {
    public static void main(String[] args) {
        // 黄鹂:创建两个对象,调用方法
        HuangLi h1 = new HuangLi();
        HuangLi h2 = new HuangLi();
        String s1 = "翠柳";
        h1.sing(s1);
        h2.sing(s1);

        // 白鹭:对象数组,循环创建 10 个对象
        String s2 = "青天";
        BaiLu[] bailus = new BaiLu[10];
        // 初始状态:数组元素全为 null
        System.out.println(Arrays.toString(bailus));

        for (int i = 0; i < 10; i++) {
            BaiLu b = new BaiLu();      // 创建白鹭对象
            b.up(s2);                    // 调用方法
            bailus[i] = b;              // 存入数组(存的是地址值)
        }
    }
}

要点:对象数组刚刚创建时,所有元素默认为 null。需要逐个 new 对象并赋值后才能使用。


5. 对象数组实战②——汽车与自行车(交通场景)

文件Car.java, Bike.java, Test02.java

定义类——汽车(Car.java)

public class Car {
    String brand;   // 品牌
    String color;   // 颜色

    public void drive() {
        System.out.println(brand + "牌的" + color + "汽车行驶.....");
    }
}

定义类——自行车(Bike.java)

public class Bike {
    String type;    // 车型

    public void ride() {
        System.out.println("我骑着" + type + "自行车在骑行.....");
    }
}

测试类 —— 单个对象 + 对象数组

public class Test02 {
    public static void main(String[] args) {
        // 单个汽车对象
        Car c = new Car();
        c.brand = "奔驰";
        c.color = "白色";
        c.drive();

        // 自行车对象数组
        Bike[] bikes = new Bike[10];
        for (int i = 0; i < 10; i++) {
            Bike b = new Bike();
            b.type = "山地";
            bikes[i] = b;
            bikes[i].ride();
        }
    }
}

要点:单个对象与对象数组混合使用,展示了面向对象建模中「1 对 N」关系的代码实现。


6. 封装实战——Person 类

文件Person.java, PersonTest.java

完整演示封装的标准实现:私有化属性 + setter/getter 方法。

实体类(Person.java)

public class Person {
    String name;        // 公开属性
    private int age;    // 私有属性:外部不能直接访问

    // setter:赋值 + 合法性校验
    public void setAge(int newAge) {
        if (newAge >= 1 && newAge < 130) {
            age = newAge;
        } else {
            System.out.println("年龄超过规定限制,赋值无效...");
        }
    }

    // getter:取值
    public int getAge() {
        return age;
    }
}

测试类(PersonTest.java)

public class PersonTest {
    public static void main(String[] args) {
        Person p = new Person();
        p.name = "张三";           // 公开属性可以直接赋值
        p.setAge(200);             // 通过 setter 赋值(会校验)
        int age = p.getAge();      // 通过 getter 取值
        System.out.println(age);   // 输出 0(因为赋值无效,age 保持默认值)
        // p.age = 20;             // 编译错误:age 是 private 的,外部无法直接访问
    }
}

7. 封装实战②——Product 商品类(this 关键字示范)

文件Product.java

完整的商品封装类,包含 4 个私有属性,每个属性都有标准的 getter/setter,并在参数与成员变量同名时使用 this 关键字。

public class Product {
    private String brand;   // 品牌
    private String name;    // 名称
    private double price;   // 价格
    private int count;      // 数量

    // setter/getter —— 使用 this 区分同名参数和成员变量
    public void setBrand(String brand) {
        this.brand = brand;  // this.brand 是成员变量,brand 是参数
    }
    public String getBrand() {
        return brand;        // 无同名冲突,this 可省略
    }

    public void setName(String name) {
        this.name = name;
    }
    public String getName() {
        return this.name;    // 加上 this 更清晰
    }

    public void setPrice(double price) {
        this.price = price;
    }
    public double getPrice() {
        return price;
    }

    public void setCount(int count) {
        this.count = count;
    }
    public int getCount() {
        return count;
    }
}

要点:当 setter 参数名与成员变量名一致时,this 不能省略,否则方法内使用的都是局部变量,赋值无效。


三、随堂练习

以下练习在 Demo02.javaDemo03.javaDemo04.java 中以注释形式列出,作为课后实现任务。

练习 1:教师类完整定义

创建 Teacher 类,包含:

  • 属性:教工号(id)、姓名(name)、年龄(age)
  • 方法:授课(teaching)——输出 id+name+age老师在授课、休息(sleep)——输出 id+name+age老师在休息

练习 2:手机类(Phone)

创建 Phone 类和 PhoneTest 测试类:

  • 属性:品牌(brand)、价格(price)
  • 方法:打电话(call)、发短信(sendMessage)

练习 3:矩形类(Rectangle)

创建矩形类,包含:

  • 属性:长度(length)、宽度(width)
  • 方法:计算矩形周长、计算矩形面积

练习 4:圆形类(Circle)

创建圆形类,包含:

  • 属性:PI(圆周率)、半径(radius)
  • 方法:计算圆形周长、计算圆形面积

练习 5:三角形类(Triangle)

创建三角形类,包含:

  • 属性:边A、边B、边C、高
  • 方法:计算三角形周长、计算三角形面积

练习 6:古诗场景建模(Demo03 练习)

分析诗句「两只黄鹂鸣翠柳,一行白鹭上青天」,创建对应类和测试类:

  • 黄鹂类(HuangLi):sing(String s) 方法
  • 白鹭类(BaiLu):up(String s) 方法
  • 测试类:创建 2 只黄鹂对象 + 10 只白鹭对象数组

练习 7:交通场景建模(Demo03 练习)

分析描述「一辆汽车在路上行驶,一队自行车并排骑行」,创建对应类和测试类:

  • 汽车类(Car):品牌、颜色属性 + drive() 方法
  • 自行车类(Bike):车型属性 + ride() 方法
  • 测试类:1 个汽车对象 + 10 辆自行车对象数组

练习 8:封装练习——学生年龄校验

参照 Person 类的封装方式,创建一个 StudentV2 类:

  • 属性:姓名(name,公开)、年龄(age,私有)
  • 要求:通过 setter 赋值时,年龄必须在 6~35 岁之间(含边界),否则提示"年龄超出学生范围,赋值无效"
  • 提供 getAge() 方法获取年龄
  • 测试类:创建对象,分别测试合法年龄和非法年龄的赋值效果

练习 9:补全 Person 类的 name 封装(Demo04 练习)

在已有 Person 类基础上,为 name 属性也添加 private 修饰,并配置对应的 setter/getter 方法。

练习 10:创建 Bird 类(Demo04 练习)

创建 Bird 类,定义 3 个私有成员变量,并对每个成员变量设置赋值和取值的方法(getter/setter),要求参数名与成员变量同名时使用 this 关键字。

练习 11:创建 Product 测试类

Product 类创建测试类 ProductTest,创建商品对象并通过 setter 赋值,通过 getter 输出所有属性值。


四、知识点总结

序号 知识点 说明 对应文件
1 面向对象思想 Java 以对象为中心,区别于 C 的面向过程 Demo01.java
2 类的定义 class 关键字定义类,包含属性和行为 Demo01.java
3 成员变量 类中方法外的变量,描述属性 Student.java, Dog.java, Teacher.java
4 成员方法 类中定义方法(无 static),描述行为 Student.java, Teacher.java
5 创建对象 类名 对象名 = new 类名(); Demo02.java, TeacherTest.java
6 调用成员 对象名.成员变量 / 对象名.成员方法() Demo02.java, TeacherTest.java
7 多对象创建 一个类可创建多个独立对象 Demo02.java
8 对象地址 直接输出对象得到 类型@哈希码 TeacherTest.java
9 成员变量 vs 局部变量 四维对比:位置、内存、生命周期、初始化值 Demo03.java
10 对象引用与内存共享 多个引用指向同一内存地址,修改互相影响 Demo03.java
11 对象数组 数组元素类型为类名,存储对象引用地址 Test01.java, Test02.java
12 循环创建对象并存入数组 for 循环中 new 对象,赋值给数组元素 Test01.java, Test02.java
13 多个类协同建模 将现实场景(古诗/交通)抽象为多个类 HuangLi.java, BaiLu.java, Car.java, Bike.java
14 封装(Encapsulation) 面向对象三大特性之一,隐藏实现细节,暴露调用方式 Demo04.java
15 private 关键字 私有权限修饰符,本类以外无法访问 Person.java
16 setter/getter 方法 对外提供公有方法赋值/取值,可做合法性校验 Person.java, PersonTest.java
17 this 关键字 区分同名的成员变量和局部变量,指向当前对象 Product.java
18 default 权限修饰符 默认访问权限,同包中可以访问 Demo04.java
19 protected 权限修饰符 受保护权限,同包+非同包子类可以访问 Demo04.java

五、拓展阅读

  1. 构造方法new 类名() 实际上是调用类的构造方法,默认有无参构造
  2. 匿名对象new Student().study(); —— 没有名字的对象,用后即弃
  3. null 与 NullPointerException:引用变量可以不指向任何对象(null),调用该引用的成员会报空指针异常
  4. 封装 vs 继承 vs 多态:三大特性后续会深入学习,继承实现代码复用,多态实现灵活扩展