Java封装 #

一、封装概述 #

封装是面向对象三大特性之一,它将数据(属性)和操作数据的方法绑定在一起,并隐藏内部实现细节。

1.1 封装的好处 #

  • 隐藏实现细节
  • 保护数据安全
  • 提供统一访问接口
  • 增强代码可维护性

二、访问修饰符 #

2.1 四种访问修饰符 #

修饰符 同一类 同一包 子类 其他
public
protected
默认
private

2.2 使用示例 #

java
public class Person {
    // private:只能在本类访问
    private String name;
    
    // 默认:同包可访问
    String address;
    
    // protected:子类和同包可访问
    protected int age;
    
    // public:任何地方可访问
    public String phone;
}

2.3 修饰符使用规则 #

java
// 类:public 或 默认
public class PublicClass { }
class DefaultClass { }

// 成员变量:通常使用private
private String name;

// 方法:根据需要选择
public void publicMethod() { }
private void privateMethod() { }
protected void protectedMethod() { }
void defaultMethod() { }

三、getter和setter #

3.1 基本用法 #

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) {
        this.age = age;
    }
}

3.2 命名规范 #

java
public class Demo {
    private String name;      // getName / setName
    private boolean active;   // isActive / setActive
    private int count;        // getCount / setCount
    
    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
    public boolean isActive() {
        return active;
    }
    
    public void setActive(boolean active) {
        this.active = active;
    }
}

3.3 在setter中添加验证 #

java
public class Person {
    private String name;
    private int age;
    
    public void setAge(int age) {
        if (age < 0 || age > 150) {
            throw new IllegalArgumentException("年龄不合法");
        }
        this.age = age;
    }
    
    public void setName(String name) {
        if (name == null || name.trim().isEmpty()) {
            throw new IllegalArgumentException("姓名不能为空");
        }
        this.name = name.trim();
    }
}

3.4 只读属性 #

java
public class Person {
    private String id;  // 只读属性
    
    public Person(String id) {
        this.id = id;
    }
    
    // 只有getter,没有setter
    public String getId() {
        return id;
    }
}

四、封装示例 #

4.1 银行账户 #

java
public class BankAccount {
    private String accountNumber;
    private String owner;
    private double balance;
    
    public BankAccount(String accountNumber, String owner) {
        this.accountNumber = accountNumber;
        this.owner = owner;
        this.balance = 0;
    }
    
    // 存款
    public void deposit(double amount) {
        if (amount <= 0) {
            throw new IllegalArgumentException("存款金额必须大于0");
        }
        balance += amount;
    }
    
    // 取款
    public void withdraw(double amount) {
        if (amount <= 0) {
            throw new IllegalArgumentException("取款金额必须大于0");
        }
        if (amount > balance) {
            throw new IllegalArgumentException("余额不足");
        }
        balance -= amount;
    }
    
    // 查询余额
    public double getBalance() {
        return balance;
    }
    
    public String getAccountNumber() {
        return accountNumber;
    }
    
    public String getOwner() {
        return owner;
    }
}

4.2 学生类 #

java
public class Student {
    private String id;
    private String name;
    private int[] scores;
    
    public Student(String id, String name) {
        this.id = id;
        this.name = name;
        this.scores = new int[0];
    }
    
    public void setScores(int[] scores) {
        for (int score : scores) {
            if (score < 0 || score > 100) {
                throw new IllegalArgumentException("分数必须在0-100之间");
            }
        }
        this.scores = scores.clone();  // 防止外部修改
    }
    
    public double getAverageScore() {
        if (scores.length == 0) return 0;
        int sum = 0;
        for (int score : scores) {
            sum += score;
        }
        return (double) sum / scores.length;
    }
    
    public String getId() {
        return id;
    }
    
    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
}

五、封装原则 #

5.1 最小化访问权限 #

java
public class Demo {
    // 成员变量:private
    private String name;
    
    // 内部方法:private
    private void validate() {
    }
    
    // 公共接口:public
    public void doSomething() {
        validate();
    }
}

5.2 保护可变对象 #

java
public class Team {
    private List<String> members = new ArrayList<>();
    
    // 错误:直接返回引用
    // public List<String> getMembers() {
    //     return members;
    // }
    
    // 正确:返回副本
    public List<String> getMembers() {
        return new ArrayList<>(members);
    }
    
    // 正确:返回不可修改视图
    public List<String> getMembersUnmodifiable() {
        return Collections.unmodifiableList(members);
    }
    
    // 通过方法修改
    public void addMember(String name) {
        members.add(name);
    }
    
    public void removeMember(String name) {
        members.remove(name);
    }
}

5.3 不可变对象 #

java
public final class ImmutablePerson {
    private final String name;
    private final int age;
    
    public ImmutablePerson(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    // 只有getter,没有setter
    public String getName() {
        return name;
    }
    
    public int getAge() {
        return age;
    }
}

六、Lombok简化 #

6.1 使用Lombok #

java
import lombok.Getter;
import lombok.Setter;

public class Person {
    @Getter @Setter
    private String name;
    
    @Getter @Setter
    private int age;
}

6.2 @Data注解 #

java
import lombok.Data;

@Data  // 自动生成getter、setter、toString、equals、hashCode
public class Person {
    private String name;
    private int age;
}

七、总结 #

概念 说明
private 只能在本类访问
默认 同包可访问
protected 子类和同包可访问
public 任何地方可访问
getter 获取属性值
setter 设置属性值

封装要点:

  • 成员变量使用private
  • 提供public的getter/setter方法
  • 在setter中添加验证逻辑
  • 保护可变对象不被直接修改
  • 遵循最小权限原则
最后更新:2026-03-26