欢迎光临
我们一直在努力

Java面向对象程序设计——类与对象

一、先给一道例题

在学生管理系统中,我们需要存储和处理学生的基本信息,例如姓名、学号、年龄和成绩。如果使用基本类型变量逐个存储,代码会非常冗余且难以维护。请用Java面向对象的思想设计一个学生信息管理系统,要求如下:

  • 设计一个Student类,包含学号(id)、姓名(name)、年龄(age)和成绩(score)四个私有属性。

  • 提供无参构造方法和带参构造方法,用于创建学生对象。

  • 为每个属性提供对应的getter和setter方法。

  • 在Student类中定义一个showInfo()方法,用于输出学生的完整信息。

  • 编写测试类,创建3个学生对象,将它们存入数组,并遍历数组输出所有学生的信息。-5-9

  • 二、解题思路

    2.1 类与对象的核心概念

    类是Java面向对象程序设计的核心概念之一。类可以被理解为一种“蓝图”或“模板”,它定义了某一类事物所共有的属性(数据)和行为(方法)。例如,现实世界中的“学生”这个概念是一个抽象的说法,它描述了学生应该具有学号、姓名、年龄等特征,以及学习、考试等行为——这就是“类”的概念。

    对象则是根据这个“蓝图”实际创建出来的具体实例。例如,“学号为2024001、姓名为张三、年龄18岁的那个具体学生”就是一个对象。类是抽象的、静态的,而对象是具体的、动态的。类是创建对象的模板,对象是类的具体表现。

    2.2 为什么要使用类与对象

    在面向对象编程出现之前,程序开发主要使用面向过程的方式,数据和操作数据的函数是分离的。这种方式在小型程序中尚可应对,但随着软件规模的增长,代码会变得越来越难以维护和扩展。

    类与对象的引入解决了这个问题,它带来了以下优势:

    • 数据封装:将数据和操作数据的方法绑定在一起,形成一个整体

    • 信息隐藏:通过访问修饰符(如private)将内部实现细节隐藏起来,只暴露必要的接口

    • 代码复用:通过创建多个对象,可以重复使用同一个类的定义

    • 符合人类思维:用计算机语言模拟现实世界的事物及其关系,更直观、易理解

    2.3 类的设计步骤

    设计一个类通常遵循以下步骤:

  • 定义类名:使用class关键字,类名通常采用大驼峰命名法(如Student、BankAccount)

  • 定义属性:声明类的成员变量,描述对象的状态特征,通常使用private修饰

  • 定义构造方法:用于创建对象时初始化属性,方法名与类名相同,没有返回值类型

  • 定义getter和setter方法:提供对外部访问私有属性的安全通道,体现封装性

  • 定义其他业务方法:根据实际需求,定义类的行为功能-5-9

  • 三、代码实现与逐行解释

    3.1 完整代码

    java

    复制

    下载

    /**
    * 学生类 – 定义学生的属性和行为
    * 这是面向对象程序设计的核心:将数据(属性)和操作(方法)封装在一起
    */
    class Student {
    // ——————– 私有属性(封装的核心)——————–
    // 属性使用private修饰,外部无法直接访问,必须通过getter/setter方法操作
    private int id; // 学号
    private String name; // 姓名
    private int age; // 年龄
    private double score; // 成绩

    // ——————– 构造方法 ——————–
    /**
    * 无参构造方法
    * 当使用new Student()时调用,创建对象后各属性为默认值
    * 注意:如果在类中定义了有参构造,建议仍然保留无参构造,因为很多框架(如Spring)依赖它
    */
    public Student() {
    System.out.println("调用了无参构造方法");
    }

    /**
    * 带参构造方法(构造方法重载)
    * 当使用new Student(2024001, "张三", 18, 95.5)时调用,一步完成对象的创建和初始化
    * @param id 学号
    * @param name 姓名
    * @param age 年龄
    * @param score 成绩
    */
    public Student(int id, String name, int age, double score) {
    this.id = id; // this.id表示当前对象的id属性,id是参数
    this.name = name;
    this.age = age;
    this.score = score;
    System.out.println("调用了带参构造方法:" + name);
    }

    // ——————– Getter和Setter方法(封装的安全通道)——————–
    /**
    * 获取学号
    * @return 学号
    */
    public int getId() {
    return id;
    }

    /**
    * 设置学号
    * @param id 学号
    */
    public void setId(int id) {
    this.id = id;
    }

    public String getName() {
    return name;
    }

    /**
    * 设置姓名
    * 可以在此方法中添加数据校验逻辑,体现封装的业务规则控制能力
    * @param name 姓名
    */
    public void setName(String name) {
    // 示例:可以在这里添加姓名不能为空的校验
    if (name == null || name.trim().isEmpty()) {
    System.out.println("姓名不能为空!");
    return;
    }
    this.name = name;
    }

    public int getAge() {
    return age;
    }

    /**
    * 设置年龄
    * 在setter方法中加入业务校验,确保数据合法性
    * @param age 年龄(应在0-120之间)
    */
    public void setAge(int age) {
    if (age < 0 || age > 120) {
    System.out.println("年龄应在0-120之间!");
    return;
    }
    this.age = age;
    }

    public double getScore() {
    return score;
    }

    /**
    * 设置成绩
    * @param score 成绩(应在0-100之间)
    */
    public void setScore(double score) {
    if (score < 0 || score > 100) {
    System.out.println("成绩应在0-100之间!");
    return;
    }
    this.score = score;
    }

    // ——————– 业务方法 ——————–
    /**
    * 展示学生信息
    * 将对象的内部状态以格式化的形式输出
    */
    public void showInfo() {
    System.out.println("学号:" + id + ",姓名:" + name + ",年龄:" + age + ",成绩:" + score);
    }

    /**
    * 判断学生是否及格
    * @return 成绩>=60返回true,否则返回false
    */
    public boolean isPass() {
    return score >= 60;
    }

    /**
    * 根据成绩返回等级
    * @return 等级(A/B/C/D/F)
    */
    public String getGrade() {
    if (score >= 90) {
    return "A";
    } else if (score >= 80) {
    return "B";
    } else if (score >= 70) {
    return "C";
    } else if (score >= 60) {
    return "D";
    } else {
    return "F";
    }
    }
    }

    /**
    * 测试类 – 演示类与对象的创建和使用
    * 面向对象编程的三大步骤:
    * 1. 定义类(已完成)→ 2. 创建对象 → 3. 调用方法
    */
    public class ClassAndObjectDemo {
    public static void main(String[] args) {
    // ——————– 方式一:使用无参构造 + setter方法 ——————–
    System.out.println("========== 方式一:无参构造 + setter ==========");
    Student stu1 = new Student(); // 创建对象,调用无参构造
    stu1.setId(2024001); // 通过setter方法设置属性
    stu1.setName("张三");
    stu1.setAge(18);
    stu1.setScore(95.5);
    stu1.showInfo(); // 调用业务方法

    // ——————– 方式二:使用带参构造(一步完成) ——————–
    System.out.println("\\n========== 方式二:带参构造 ==========");
    Student stu2 = new Student(2024002, "李四", 19, 82.0);
    stu2.showInfo();
    System.out.println("是否及格:" + (stu2.isPass() ? "是" : "否"));
    System.out.println("成绩等级:" + stu2.getGrade());

    Student stu3 = new Student(2024003, "王五", 20, 57.5);
    stu3.showInfo();
    System.out.println("是否及格:" + (stu3.isPass() ? "是" : "否"));
    System.out.println("成绩等级:" + stu3.getGrade());

    // ——————– 对象数组的使用 ——————–
    System.out.println("\\n========== 学生对象数组 ==========");
    // 声明并创建学生对象数组,长度为3
    Student[] students = new Student[3];
    students[0] = stu1; // 将已创建的对象存入数组
    students[1] = stu2;
    students[2] = stu3;

    // 遍历数组,输出所有学生信息
    System.out.println("所有学生信息如下:");
    for (int i = 0; i < students.length; i++) {
    System.out.print("第" + (i + 1) + "位学生:");
    students[i].showInfo();
    }

    // ——————– 增强for循环遍历 ——————–
    System.out.println("\\n========== 增强for循环遍历 ==========");
    for (Student s : students) {
    s.showInfo();
    }
    }
    }

    运行结果:

    text

    复制

    下载

    ========== 方式一:无参构造 + setter ==========
    调用了无参构造方法
    学号:2024001,姓名:张三,年龄:18,成绩:95.5

    ========== 方式二:带参构造 ==========
    调用了带参构造方法:李四
    学号:2024002,姓名:李四,年龄:19,成绩:82.0
    是否及格:是
    成绩等级:B
    调用了带参构造方法:王五
    学号:2024003,姓名:王五,年龄:20,成绩:57.5
    是否及格:否
    成绩等级:F

    ========== 学生对象数组 ==========
    所有学生信息如下:
    第1位学生:学号:2024001,姓名:张三,年龄:18,成绩:95.5
    第2位学生:学号:2024002,姓名:李四,年龄:19,成绩:82.0
    第3位学生:学号:2024003,姓名:王五,年龄:20,成绩:57.5

    ========== 增强for循环遍历 ==========
    学号:2024001,姓名:张三,年龄:18,成绩:95.5
    学号:2024002,姓名:李四,年龄:19,成绩:82.0
    学号:2024003,姓名:王五,年龄:20,成绩:57.5

    3.2 逐行代码解释

    ① 类的定义与属性声明

    java

    复制

    下载

    class Student {
    private int id;
    private String name;
    private int age;
    private double score;
    }

    • class关键字用于定义一个类,Student是类名,遵循大驼峰命名法

    • private是访问修饰符,表示这些属性只能在当前类内部被访问,外部无法直接读取或修改

    • 这种将属性隐藏起来的做法就是封装,它保护了数据的完整性和安全性

    ② 构造方法

    java

    复制

    下载

    public Student() {
    System.out.println("调用了无参构造方法");
    }

    public Student(int id, String name, int age, double score) {
    this.id = id;
    this.name = name;
    this.age = age;
    this.score = score;
    }

    • 构造方法是创建对象的入口,方法名必须与类名完全相同,且没有返回值类型(void也不行)

    • 无参构造在没有自定义构造方法时由编译器自动提供;但如果手动添加了有参构造,编译器不再提供无参构造,建议手动保留

    • this关键字用于区分成员变量和参数——当成员变量名和参数名相同时,this.id指的是当前对象的id属性,而id指的是传入的参数-9

    ③ Setter方法中的业务校验

    java

    复制

    下载

    public void setName(String name) {
    if (name == null || name.trim().isEmpty()) {
    System.out.println("姓名不能为空!");
    return;
    }
    this.name = name;
    }

    • Setter方法不仅仅是简单的赋值,还可以加入业务逻辑验证

    • 这样做的好处是:数据验证逻辑集中在一处,避免在多个调用处重复编写校验代码

    • 如果以后校验规则发生变化,只需要修改这一个方法即可——这正是封装带来的维护性优势

    ④ 对象数组

    java

    复制

    下载

    Student[] students = new Student[3];
    students[0] = stu1;

    • 对象数组的声明与基本类型数组类似:类名[] 数组名 = new 类名[长度]

    • 与基本类型数组不同,对象数组的每个位置存储的是对象的引用(即对象在内存中的地址),而不是对象本身

    • 创建数组后,需要将已经创建的对象存入数组,然后才能使用

    ⑤ 增强for循环(for-each)

    java

    复制

    下载

    for (Student s : students) {
    s.showInfo();
    }

    • 增强for循环是Java 5引入的语法糖,专门用于遍历数组和集合

    • 语法:for (元素类型 变量名 : 数组/集合)

    • 每次循环,变量s会依次指向数组中的每一个元素,代码更加简洁、不易出错-5

    四、总结

    通过以上学生类的设计与使用,我们可以总结出以下几个核心要点:

    类与对象的本质关系

    • 类是对象的“蓝图”或“模板”,定义了对象应该具备的属性和行为

    • 对象是根据类创建出来的具体实例,一个类可以创建无数个对象

    • 类是静态的概念(存在于代码层面),对象是动态的概念(存在于运行时内存中)

    创建对象的标准流程

    • 声明对象引用:类名 对象名;

    • 实例化对象:对象名 = new 类名();(new关键字在堆内存中分配空间)

    • 合并写法:类名 对象名 = new 类名();

    类的核心组成部分及作用

    • 属性(成员变量):描述对象的状态特征,通常设为private

    • 构造方法:创建对象时的初始化入口,方法名与类名相同,无返回值

    • getter/setter方法:对外访问私有属性的安全通道,可在此添加业务校验逻辑

    • 业务方法:定义对象的具体行为功能(如showInfo、isPass等)

    封装带来的核心价值

    • 数据安全性:通过private隐藏内部数据,外部无法随意篡改

    • 数据合法性:在setter方法中加入验证逻辑,确保对象始终处于合法状态

    • 降低耦合度:外部只依赖方法,不依赖内部实现细节

    • 提高可维护性:修改内部实现时不影响外部调用代码

    对象数组的要点

    • 对象数组存储的是对象的引用(地址),不是对象本身

    • 先创建数组,再创建对象并存入,最后才能使用

    • 遍历对象数组时,注意处理可能存在的null元素

    命名规范建议

    • 类名:大驼峰命名法,如Student、BankAccount

    • 变量名/方法名:小驼峰命名法,如studentName、showInfo

    • 常量名:全大写+下划线,如MAX_SCORE

    五、更多练习题目推荐

    以下是可以直接访问的Java类与对象相关练习题(请复制链接后自行替换 [colon] 为 :,[dot] 为 .):

    https://www.luogu.com.cn/problem/P5740

    https://www.luogu.com.cn/problem/P5741

    https://www.luogu.com.cn/problem/P5742

    https://blog.csdn.net/2401_87890252/article/details/152521736

    https://blog.csdn.net/2501_91241024/article/details/149905735

    https://blog.csdn.net/m0_63792223/article/details/129464959

    以上洛谷题目都是经典的面向对象练习题,P5740要求封装学生类并找出总分最高的学生,P5741要求实现学生之间的相似度比较,P5742则需要计算综合评分并判断等级-3-6。练习建议:可以尝试在Student类中增加更多属性(如班级、电话),并扩展相应的业务方法(如修改密码、计算平均分等),进一步熟悉类与对象的设计流程。

    赞(0)
    未经允许不得转载:171主机测评 » Java面向对象程序设计——类与对象
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址