第21章

Java类和对象

理解面向对象编程的核心概念,掌握类的定义和对象的使用

学习目标

面向对象编程概述

面向对象编程(Object-Oriented Programming,OOP)是一种编程范式,它将现实世界中的事物抽象为程序中的对象。Java是一门纯面向对象的编程语言,理解类和对象的概念是掌握Java编程的关键。

什么是面向对象编程?
面向对象编程是一种程序设计思想,它将数据和操作数据的方法封装在一起,形成对象。通过对象之间的交互来完成程序的功能。

类(Class)

类的定义:
public class Student {
    // 属性(实例变量)
    private String name;
    private int age;
    
    // 构造方法
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    // 方法
    public void study() {
        System.out.println(name + "正在学习");
    }
}
  • 对象的模板或蓝图
  • 定义对象的属性和行为
  • 使用class关键字定义
  • 包含属性、构造方法和方法

对象(Object)

对象的创建和使用:
// 创建对象
Student student = new Student("张三", 20);

// 调用方法
student.study();

// 输出:张三正在学习
  • 类的实例
  • 具有类定义的属性和行为
  • 使用new关键字创建
  • 每个对象都有独立的状态

类的基本结构

Java类由以下几个主要部分组成:属性(实例变量)、构造方法、实例方法和静态成员。让我们通过一个完整的学生类示例来了解这些组成部分。

完整的学生类示例:
/**
 * 学生类示例
 * 演示类的基本结构和面向对象编程概念
 */
public class Student {
    
    // 实例变量(属性)
    private String name;        // 学生姓名
    private int age;           // 学生年龄
    private String studentId;  // 学号
    private String major;      // 专业
    
    // 默认构造方法
    public Student() {
        this.name = "未知";
        this.age = 0;
        this.studentId = "000000";
        this.major = "未定";
    }
    
    // 带参数的构造方法
    public Student(String name, int age, String studentId, String major) {
        this.name = name;
        this.age = age;
        this.studentId = studentId;
        this.major = major;
    }
    
    // 重载构造方法
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
        this.studentId = "000000";
        this.major = "未定";
    }
    
    // Getter方法
    public String getName() {
        return name;
    }
    
    public int getAge() {
        return age;
    }
    
    // Setter方法
    public void setName(String name) {
        this.name = name;
    }
    
    public void setAge(int age) {
        if (age > 0 && age < 150) {
            this.age = age;
        } else {
            System.out.println("年龄输入不合法!");
        }
    }
    
    // 实例方法
    public void study() {
        System.out.println(name + "正在学习");
    }
    
    public void study(String subject) {
        System.out.println(name + "正在学习" + subject);
    }
    
    public void displayInfo() {
        System.out.println("=== 学生信息 ===");
        System.out.println("姓名: " + name);
        System.out.println("年龄: " + age + "岁");
        System.out.println("学号: " + studentId);
        System.out.println("专业: " + major);
    }
}
💻 查看完整代码 - 在线IDE体验

构造方法详解

构造方法是一种特殊的方法,用于创建对象时初始化对象的状态。构造方法的名称必须与类名相同,且没有返回类型。

默认构造方法

public Student() {
    this.name = "未知";
    this.age = 0;
    this.studentId = "000000";
    this.major = "未定";
}
  • 无参数的构造方法
  • 提供默认的初始化值
  • 如果没有定义构造方法,Java会提供默认构造方法

带参数构造方法

public Student(String name, int age, 
               String studentId, String major) {
    this.name = name;
    this.age = age;
    this.studentId = studentId;
    this.major = major;
}
  • 接受参数进行初始化
  • 可以有多个不同参数的构造方法
  • 构造方法重载
注意:一旦定义了带参数的构造方法,Java就不会自动提供默认构造方法。如果需要默认构造方法,必须显式定义。

静态变量和静态方法

静态成员属于类本身,而不是某个特定的对象。所有对象共享静态变量,静态方法可以通过类名直接调用。

汽车类示例 - 演示静态成员:
public class Car {
    
    // 静态变量(类变量)
    private static int totalCars = 0;
    
    // 实例变量
    private String brand;
    private String model;
    private double price;
    
    // 构造方法
    public Car(String brand, String model, double price) {
        this.brand = brand;
        this.model = model;
        this.price = price;
        totalCars++; // 每创建一个对象,总数加1
    }
    
    // 静态方法 - 获取汽车总数
    public static int getTotalCars() {
        return totalCars;
    }
    
    // 静态方法 - 比较两辆车的价格
    public static void comparePrices(Car car1, Car car2) {
        if (car1.price > car2.price) {
            System.out.println(car1.brand + " " + car1.model + " 比 " + 
                             car2.brand + " " + car2.model + " 贵");
        } else if (car1.price < car2.price) {
            System.out.println(car2.brand + " " + car2.model + " 比 " + 
                             car1.brand + " " + car1.model + " 贵");
        } else {
            System.out.println("两辆车价格相同");
        }
    }
    
    // 实例方法
    public void displayInfo() {
        System.out.println("品牌: " + brand);
        System.out.println("型号: " + model);
        System.out.println("价格: ¥" + price);
    }
}
特性 实例成员 静态成员
归属 属于对象 属于类
内存分配 每个对象都有自己的副本 所有对象共享一份
访问方式 通过对象访问 通过类名或对象访问
生命周期 随对象创建和销毁 随类加载和卸载

封装的概念和实现

封装是面向对象编程的重要原则之一,它将数据和操作数据的方法结合在一起,并隐藏内部实现细节,只暴露必要的接口。

银行账户类 - 封装示例:
public class BankAccount {
    
    // 私有属性,外部无法直接访问
    private String accountNumber;
    private String accountHolder;
    private double balance;
    private String password;
    
    // 构造方法
    public BankAccount(String accountNumber, String accountHolder, 
                      double initialBalance, String password) {
        this.accountNumber = accountNumber;
        this.accountHolder = accountHolder;
        this.password = password;
        
        // 验证初始余额
        if (initialBalance >= 0) {
            this.balance = initialBalance;
        } else {
            this.balance = 0;
            System.out.println("初始余额不能为负数,已设置为0");
        }
    }
    
    // 存款方法
    public boolean deposit(double amount, String inputPassword) {
        // 验证密码
        if (!verifyPassword(inputPassword)) {
            System.out.println("密码错误,存款失败!");
            return false;
        }
        
        // 验证金额
        if (amount <= 0) {
            System.out.println("存款金额必须大于0!");
            return false;
        }
        
        balance += amount;
        System.out.println("存款成功!当前余额: ¥" + balance);
        return true;
    }
    
    // 取款方法
    public boolean withdraw(double amount, String inputPassword) {
        if (!verifyPassword(inputPassword)) {
            System.out.println("密码错误,取款失败!");
            return false;
        }
        
        if (amount <= 0) {
            System.out.println("取款金额必须大于0!");
            return false;
        }
        
        if (amount > balance) {
            System.out.println("余额不足,取款失败!");
            return false;
        }
        
        balance -= amount;
        System.out.println("取款成功!当前余额: ¥" + balance);
        return true;
    }
    
    // 私有方法 - 验证密码
    private boolean verifyPassword(String inputPassword) {
        return password != null && password.equals(inputPassword);
    }
    
    // 只提供必要的getter方法
    public String getAccountNumber() {
        return accountNumber;
    }
    
    public String getAccountHolder() {
        return accountHolder;
    }
    
    // 注意:不提供getPassword()和setBalance()等方法
    // 这样可以保护敏感数据的安全性
}
封装的好处:
  • 数据安全:私有属性防止外部直接修改
  • 数据验证:通过方法控制数据的修改
  • 隐藏实现:内部实现细节对外不可见
  • 易于维护:修改内部实现不影响外部代码

类和对象的最佳实践

编程最佳实践

✅ 好的做法

  • 使用有意义的类名和方法名
    public class BankAccount {  // 清晰的类名
        public boolean withdraw(double amount) { ... }  // 清晰的方法名
    }
  • 合理使用访问修饰符
    private String password;     // 敏感数据设为私有
    public void displayInfo() { // 公共接口设为公有
  • 提供构造方法重载
    public Student() { ... }                    // 默认构造
    public Student(String name, int age) { ... } // 带参构造
  • 实现数据验证
    public void setAge(int age) {
        if (age > 0 && age < 150) {
            this.age = age;
        }
    }

❌ 应该避免的做法

  • 直接暴露内部数据
    public double balance;  // 不安全,应该设为私有
  • 缺少数据验证
    public void setAge(int age) {
        this.age = age;  // 没有验证,可能设置无效值
    }
  • 过度复杂的类
    // 一个类承担太多责任
    class StudentTeacherManagerSystem { ... }
  • 不合理的方法命名
    public void doSomething() { ... }  // 方法名不明确
    public void a() { ... }            // 方法名无意义

章节总结