封装

封装是面向对象的核心特性之一,本课学习如何保护对象的数据。

什么是封装

封装是把数据(属性)和操作数据的方法绑定在一起,隐藏内部实现细节。

封装的好处

好处 说明
数据保护 防止外部直接访问和修改
灵活性 可以在setter中添加验证逻辑
可维护性 内部实现改变不影响外部调用

访问修饰符

Java有四种访问修饰符,控制类、属性、方法的访问范围。

修饰符 同类 同包 子类 不同包
public
protected
默认(无修饰符)
private

示例:访问修饰符

JAVA
public class Person {
    public String name;      // 公开的,任何地方都能访问
    protected int age;       // 受保护的,同包和子类能访问
    String address;          // 默认,同包能访问
    private double salary;   // 私有的,只有本类能访问
}
▶ 试一试
💡 建议: 属性通常用private,通过getter/setter方法访问。

getter和setter

为什么需要getter/setter

JAVA
public class Person {
    private String name;
    private int age;
    
    // getter
    public String getName() {
        return name;
    }
    
    // setter
    public void setName(String name) {
        this.name = name;
    }
    
    public int getAge() {
        return age;
    }
    
    public void setAge(int age) {
        // 在setter中添加验证逻辑
        if (age >= 0 && age <= 150) {
            this.age = age;
        } else {
            System.out.println("年龄不合法");
        }
    }
}

示例:getter/setter使用

JAVA
public class PersonTest {
    public static void main(String[] args) {
        Person p = new Person();
        
        // 通过setter设置值
        p.setName("Alice");
        p.setAge(25);
        
        // 通过getter获取值
        System.out.println("姓名:" + p.getName());
        System.out.println("年龄:" + p.getAge());
        
        // setter中有验证逻辑
        p.setAge(-5);  // 输出:年龄不合法
    }
}
▶ 试一试

JavaBean规范

JavaBean是一种特殊的Java类,遵循特定规范。

JavaBean规范

规范 说明
属性私有 private修饰
提供getter/setter getXxx()setXxx()
无参构造方法 必须有
实现Serializable 可选,用于序列化

示例:标准JavaBean

JAVA
import java.io.Serializable;

public class User implements Serializable {
    // 属性私有
    private String username;
    private String password;
    private int age;
    
    // 无参构造
    public User() {}
    
    // 有参构造
    public User(String username, String password, int age) {
        this.username = username;
        this.password = password;
        this.age = age;
    }
    
    // getter/setter
    public String getUsername() {
        return username;
    }
    
    public void setUsername(String username) {
        this.username = username;
    }
    
    public String getPassword() {
        return password;
    }
    
    public void setPassword(String password) {
        if (password.length() >= 6) {
            this.password = password;
        } else {
            System.out.println("密码长度不能少于6位");
        }
    }
    
    public int getAge() {
        return age;
    }
    
    public void setAge(int age) {
        if (age >= 0 && age <= 150) {
            this.age = age;
        } else {
            System.out.println("年龄不合法");
        }
    }
    
    @Override
    public String toString() {
        return "User{username='" + username + "', age=" + age + "}";
    }
}
▶ 试一试

封装的实际应用

示例:银行账户

JAVA
public class BankAccount {
    private String accountId;
    private double balance;
    private String owner;
    
    public BankAccount(String accountId, String owner) {
        this.accountId = accountId;
        this.owner = owner;
        this.balance = 0;
    }
    
    // 存款
    public void deposit(double amount) {
        if (amount > 0) {
            balance += amount;
            System.out.println("存入:" + amount + ",余额:" + balance);
        } else {
            System.out.println("存款金额必须大于0");
        }
    }
    
    // 取款
    public void withdraw(double amount) {
        if (amount > 0 && amount <= balance) {
            balance -= amount;
            System.out.println("取出:" + amount + ",余额:" + balance);
        } else if (amount > balance) {
            System.out.println("余额不足");
        } else {
            System.out.println("取款金额必须大于0");
        }
    }
    
    // 查询余额
    public double getBalance() {
        return balance;
    }
    
    public void showInfo() {
        System.out.println("账户:" + accountId + ",户主:" + owner + ",余额:" + balance);
    }
    
    public static void main(String[] args) {
        BankAccount account = new BankAccount("10001", "Alice");
        account.showInfo();  // 账户:10001,户主:Alice,余额:0.0
        
        account.deposit(1000);  // 存入:1000.0,余额:1000.0
        account.deposit(500);   // 存入:500.0,余额:1500.0
        account.withdraw(200);  // 取出:200.0,余额:1300.0
        account.withdraw(2000); // 余额不足
    }
}
▶ 试一试

示例:商品价格验证

JAVA
public class Product {
    private String name;
    private double price;
    private int stock;
    
    public Product(String name, double price, int stock) {
        this.name = name;
        setPrice(price);
        setStock(stock);
    }
    
    public String getName() {
        return name;
    }
    
    public double getPrice() {
        return price;
    }
    
    public void setPrice(double price) {
        if (price >= 0) {
            this.price = price;
        } else {
            System.out.println("价格不能为负");
        }
    }
    
    public int getStock() {
        return stock;
    }
    
    public void setStock(int stock) {
        if (stock >= 0) {
            this.stock = stock;
        } else {
            System.out.println("库存不能为负");
        }
    }
    
    // 计算总价
    public double getTotalPrice(int quantity) {
        if (quantity > 0 && quantity <= stock) {
            return price * quantity;
        } else {
            System.out.println("购买数量不合法");
            return 0;
        }
    }
    
    @Override
    public String toString() {
        return name + " - ¥" + price + " (库存:" + stock + ")";
    }
}
▶ 试一试

getter/setter的命名规则

属性类型 getter setter
boolean married isMarried() setMarried()
String name getName() setName()
int age getAge() setAge()
⚠️ 特殊: boolean类型的getter用is开头,不是get

❓ 常见问题

Q 为什么不直接用public属性?
A public属性无法控制访问,setter可以添加验证逻辑,保护数据安全。
Q 所有属性都需要getter/setter吗?
A 不一定。只读属性只提供getter,只写属性只提供setter。
Q 构造方法和setter有什么区别?
A 构造方法在创建对象时调用,setter在对象创建后修改属性。

📖 小节

📝 作业

  1. Student类: 定义Student类,封装属性,score在0-100之间验证
  2. Date类: 定义日期类,封装年月日,提供日期验证
  3. BankAccount改进: 添加密码验证,取款需要密码

下一课

下一课我们将学习 继承,了解代码复用的重要机制。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏