20260721-笔记.md 16 KB

JavaSE 基础 — Day07 笔记

日期:2026-07-21
项目c260721
作者:WanJL


一、构造方法(Constructor)

1. 构造方法的引出——为什么需要构造方法?

文件Demo01.java

在面向对象编程中,我们创建对象后通常通过 setter 方法为属性赋值。但有些属性(如性别 gender)是在对象创建时就已确定的,如果先创建对象再通过 setter 设置,虽然代码没有错误,但不符合现实逻辑。

// 传统方式:先造人,再取名、设性别
Person p = new Person();
p.setName("张三");     // 人出生后取名,符合逻辑
p.setGender("男");     // 人出生后再设置性别,代码没问题但不合常理

// 需求:在创建人的时候,就要给性别和年龄等属性赋值

结论:需要在创建对象的同时,为某些属性赋予初始值——这就用到了 构造方法(构造器)


2. 构造方法的格式

文件Demo01.java

构造方法是一种特殊的方法,具有以下特点:

特点 说明
方法名 与类名完全一致(大小写也相同)
返回值类型 没有返回值类型,连 void 都没有
返回值 不能使用 return 带回结果,因为直接返回新构造的对象
调用方式 创建对象时自动调用,不能手动调用
public class Person {
    private String name;
    private int age;
    private String gender;

    // 构造方法格式:访问权限修饰符 类名() { }
    public Person() {
        // 构造方法体
    }
}

3. 默认构造方法

文件Demo01.java

  • Java 中所有的类在创建对象时,都会默认调用一个构造方法
  • 每个类都默认有一个隐藏的无参构造方法
  • 当我们显式定义了构造方法后,自定义的构造方法会覆盖默认隐藏的构造方法
  • 默认构造方法的访问权限修饰符与类的修饰符相同(类用 public,构造方法也是 public

    // 类默认自带的无参构造方法(隐藏):
    // public Person() { }
    

注意:如果类的构造方法被设置为 private,外部就无法创建该类的对象了。


4. 无参构造方法——对象创建时执行初始化操作

文件Person.java

我们可以在无参构造方法中编写代码,在创建对象时自动执行。

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

    // 无参构造方法:创建对象时自动执行
    public Person() {
        System.out.println("这是一个构造方法....我开始造人啦");
        // 可以在构造方法中直接给属性赋固定值
        this.gender = "男";
    }

    // getter/setter 省略...
}

测试类(PersonTest.java)

public class PersonTest {
    public static void main(String[] args) {
        // 创建对象时,自动调用并执行对应的构造方法
        Person p = new Person();   // 输出:这是一个构造方法....我开始造人啦
        System.out.println(p.getGender());  // 输出:男
    }
}

5. 构造方法的重载(Overload)

文件Person.java

构造方法可以像普通方法一样定义参数,多个同名构造方法只要参数列表不同(参数类型不同或参数个数不同),就称为 构造方法重载

注意:如果参数类型相同、个数相同,仅参数名不同,不算重载。

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

    // ① 无参构造方法
    public Person() {
        System.out.println("这是一个构造方法....我开始造人啦");
        this.gender = "男";
    }

    // ② 单参数构造方法:仅设置性别
    public Person(String gender) {
        this.gender = gender;
    }

    // ③ 双参数构造方法:设置姓名和性别
    public Person(String name, String gender) {
        this.name = name;
        this.gender = gender;
    }

    // ④ 三参数构造方法:设置姓名、年龄、性别
    public Person(String name, int age, String gender) {
        this.name = name;
        this.age = age;
        this.gender = gender;
    }
}

6. 有参构造方法的调用

文件PersonTest.java, StudentTest.java

创建对象时,根据传入的参数列表自动匹配对应的构造方法。

public class PersonTest {
    public static void main(String[] args) {
        // 调用无参构造方法
        Person p = new Person();
        System.out.println(p.getGender());  // 输出:男(在无参构造中写死的)

        // 直接输出对象,得到地址
        System.out.println(p);              // course.Person@地址
        System.out.println(new Person());   // course.Person@地址

        // 调用有参构造方法:传入性别
        Person p1 = new Person("女");
        System.out.println(p1.getGender()); // 输出:女
    }
}
public class StudentTest {
    public static void main(String[] args) {
        // 调用三参构造方法创建 Student 对象
        Student s = new Student("张三", 25, "男");
    }
}

7. 构造方法的核心要点总结

序号 要点 说明
1 方法名必须与类名一致 大小写也必须相同
2 没有返回值类型 void 都不写
3 不能 return 返回值 直接返回新创建的对象
4 创建对象时自动调用 每创建一个对象,执行一次构造方法
5 不能手动调用 构造方法只能通过 new 关键字自动触发
6 默认构造方法 每个类默认有一个隐藏的无参构造方法
7 定义后覆盖默认 显式定义构造方法后,默认的会被覆盖
8 可重载 参数列表不同即可定义多个构造方法
9 权限修饰符与类一致 默认构造方法的权限与类的修饰符相同
10 private 构造方法 可阻止外部创建对象

8. 完整示例:Person 类 + 4 种构造方法

文件Person.java

完整的 Person 类包含 3 个私有属性和 4 个重载的构造方法:

package course;

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

    // 构造方法 —— 4 种重载形式
    public Person() {                              // 无参
        System.out.println("这是一个构造方法....我开始造人啦");
        this.gender = "男";
    }
    public Person(String gender) {                 // 1 参:性别
        this.gender = gender;
    }
    public Person(String name, String gender) {    // 2 参:姓名 + 性别
        this.name = name;
        this.gender = gender;
    }
    public Person(String name, int age, String gender) {  // 3 参:姓名 + 年龄 + 性别
        this.name = name;
        this.age = age;
        this.gender = gender;
    }

    // getter / setter
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public int getAge() { return age; }
    public void setAge(int age) { this.age = age; }
    public String getGender() { return gender; }
    public void setGender(String gender) { this.gender = gender; }
}

9. private 构造方法——禁止外部创建对象

文件Student.java

如果将构造方法用 private 修饰,外部就无法创建该类的对象。这在设计模式中的 单例模式 中会用到。

public class Student {
    // 私有构造方法:外部无法使用 new Student() 来创建对象
    /*
    private Student() {
        System.out.println("构造学生对象....");
    }
    */

    private String name;
    private int age;
    private String gender;

    // 公开的无参构造方法(注释掉私有构造后使用)
    public Student() {
    }

    // 有参构造方法
    public Student(String name, int age, String gender) {
        this.name = name;
        this.age = age;
        this.gender = gender;
    }
}

二、课后作业回顾

1. 题目 8:Fisher-Yates 洗牌算法(数组随机打乱)

文件homework/c260717/Demo_08.java

使用 Fisher-Yates 洗牌算法 实现数组元素的随机打乱。核心思路:从后往前遍历,每次将当前元素与随机位置的元素交换。

package homework.c260717;

import java.util.Arrays;
import java.util.Random;

public class Demo_08 {
    public static void shuffleArray(int[] arr) {
        Random ran = new Random();
        // Fisher-Yates 洗牌:从后往前遍历
        for (int i = arr.length - 1; i > 1; i--) {
            int j = ran.nextInt(i + 1);  // 生成 [0, i] 的随机索引
            int t = arr[i];
            arr[i] = arr[j];
            arr[j] = t;                  // 交换 arr[i] 和 arr[j]
        }
    }

    public static void main(String[] args) {
        int[] arr = {1, 2, 3, 4, 5, 6, 7};
        System.out.println("打乱前:" + Arrays.toString(arr));
        shuffleArray(arr);
        System.out.println("打乱后:" + Arrays.toString(arr));
    }
}

知识点Random.nextInt(n) 生成 [0, n) 范围的随机整数;Fisher-Yates 算法确保每个排列等概率出现。


2. Emp 员工类——封装与 setter 校验

文件homework/c260720/Emp.java

package homework.c260720;

public class Emp {
    private String id;
    private String name;
    private double salary;

    // getter/setter —— salary 的 setter 加入校验
    public void setSalary(double salary) {
        if (salary < 0) {
            System.out.println("薪资不能为负数");
        } else {
            this.salary = salary;
        }
    }

    public void work() {
        System.out.println("工号" + id + "的员工" + name + "正在工作......");
    }
}

测试类(EmpTest.java)

public class EmpTest {
    public static void main(String[] args) {
        Emp emp = new Emp();
        emp.setId("a1001");
        emp.setName("张三");
        emp.setSalary(-10000);  // 输出:薪资不能为负数
        emp.work();             // 输出:工号a1001的员工张三正在工作......
    }
}

3. MathTools 工具类——回文数判断

文件homework/c260720/MathTools.java

回文数判断算法:通过循环逐位取余、反序拼接,最后比较反序结果与原数是否相等。

public class MathTools {
    /**
     * 判断一个整数是否为回文数(正着读反着读一样)
     */
    public boolean isPalindrome(int num) {
        int a = num;       // 保留原始值
        int sum = 0;
        while (num > 0) {
            int b = num % 10;     // 获取最后一位
            sum = sum * 10 + b;   // 拼接到反序结果
            num /= 10;            // 缩小 10 倍
        }
        return sum == a;          // 比较反序结果与原值
    }
}

测试用例12321true(回文),12345false1221true


4. Student 学生类(homework 版)——封装 + 信息展示

文件homework/c260720/Student.java

public class Student {
    private String name;
    private int age;
    private String className;

    // getter/setter 省略...

    public void showInfo() {
        System.out.println("姓名:" + this.name);
        System.out.println("年龄:" + this.age);
        System.out.println("班级:" + this.className);
    }

    public void study(String course) {
        System.out.println(this.name + "正在学习" + course);
    }
}

测试类(StudentTest.java)

public class StudentTest {
    public static void main(String[] args) {
        Student s = new Student();
        s.setName("张三");
        s.setAge(25);
        s.setClassName("J260713");
        s.showInfo();
        s.study("Java");
    }
}

三、随堂练习

以下练习基于本日所学构造方法知识点,请在 Demo01.javaPerson.java 等参考代码基础上完成。

练习 1:为 Person 类扩充构造方法

基于已有的 Person 类,添加以下构造方法:

  • 无参构造:输出"Person 对象创建"
  • 单参构造:只传入年龄(int age),将年龄赋值给成员变量
  • 双参构造:传入姓名和年龄
  • 测试类中分别调用 3 种构造方法创建对象

练习 2:构造方法权限验证

参照 Student.java 中的 private 构造方法示例:

  1. 创建一个 Dog 类,将无参构造设为 private
  2. 在测试类中尝试 new Dog(),观察编译错误
  3. 增加一个 public 的有参构造方法,测试是否能正常创建对象

练习 3:图书类(Book)构造方法设计

创建 Book 类,包含:

  • 属性:书名(title,私有)、作者(author,私有)、价格(price,私有)
  • 构造方法
    • 无参构造
    • 全参构造(3 个参数)
  • 方法showInfo() 输出图书信息
  • 测试类:分别使用无参构造 + setter 赋值,以及全参构造直接赋值两种方式创建图书对象

练习 4:构造方法重载练习

创建 Calculator 类:

  • 属性:操作数1(num1)、操作数2(num2)
  • 构造方法
    • 无参构造(num1=0, num2=0)
    • 单参构造(num1=参数, num2=0)
    • 双参构造(num1+num2)
  • 方法add() 返回两数之和、show() 输出两个操作数

练习 5:补全 MathTools 工具类

补全 MathTools 类中未实现的方法:

  • printPrime():输出 1~100 之间的所有质数,每行 5 个
  • printSum(int n, int m):计算并输出 n~m 之间所有整数的累加和
  • getLuckyNumber():使用 Random 生成 1~100 之间的幸运数字并返回

练习 6:补全 SortUtils 冒泡排序

补全 SortUtils 类中的 bubbleSort(int[] arr) 方法,实现冒泡排序算法。


四、知识点总结

序号 知识点 说明 对应文件
1 构造方法概念 创建对象时自动调用的特殊方法,用于初始化属性 Demo01.java
2 构造方法格式 方法名=类名,无返回值类型(无 void),无 return Demo01.java
3 默认构造方法 每个类默认有一个隐藏的无参构造方法,权限与类一致 Demo01.java
4 构造方法覆盖 显式定义构造方法后,默认构造方法被覆盖 Demo01.java
5 无参构造方法 无参数的构造方法,可执行初始化代码 Person.java
6 有参构造方法 可带参数的构造方法,通过参数为属性赋值 Person.java
7 构造方法重载 参数列表不同的多个同名构造方法 Person.java
8 this 在构造方法中 区分同名的参数和成员变量 Person.java
9 构造方法调用 通过 new 类名(参数) 自动匹配并调用 PersonTest.java, StudentTest.java
10 private 构造方法 私有构造方法阻止外部创建对象 Student.java
11 输出对象地址 直接输出对象引用得到 包名.类名@哈希码 PersonTest.java
12 Fisher-Yates 洗牌 数组随机打乱算法(从后往前遍历 + 随机交换) homework/c260717/Demo_08.java
13 setter 参数校验 在 setter 方法中加入业务规则校验 homework/c260720/Emp.java
14 回文数判断 逐位取余反序后与原数比较 homework/c260720/MathTools.java

五、拓展阅读

  1. 构造方法与普通方法的区别:构造方法创建对象时自动执行,普通方法需要手动调用;构造方法无返回值,普通方法可以有返回值
  2. 单例模式(Singleton):将构造方法私有化,通过静态方法提供唯一实例,是设计模式中的经典模式
  3. this() 构造方法间调用:在一个构造方法中使用 this(参数) 调用另一个构造方法,必须写在第一行
  4. super() 与父类构造方法:子类构造方法中默认调用父类无参构造 super(),后续在继承中会深入学习
  5. 对象初始化顺序:静态代码块 → 构造代码块 → 构造方法,后续逐渐深入