首页 > 编程笔记 > Java笔记 阅读:16

封装是什么,Java封装的具体实现(附带实例)

封装性是面向对象编程的很重要的一种特性,所谓封装就是将内部细节包装起来,从外部看就是一个单一的整体。

对于 Java 而言,封装主要是指将 Java 类中的某些属性隐藏起来,从而防止被外部随意访问和修改,如果要访问则必须通过规定的方法,比如将某个类的属性 data 设置为 private,然后提供 setData() 和 getData() 两个方法来对其进行访问。

举个简单的例子:
class Account {
    private double balance = 0;

    public void withdraw(double num) {
        if (num < 0)
            System.out.println("error");
        else
            balance = balance - num;
    }

    public void deposit(double num) {
        if (num < 0)
              System.out.println("error");
        else
              balance = balance + num;
    }

    public double getBalance() {
        return balance;
    }
}

public class EncapsulationTest {
    public static void main(String[] args) {
        Account account = new Account();
        account.deposit(20.5);
        account.deposit(20.5);
        account.withdraw(10);
        System.out.println("the balance is " + account.getBalance());
    }
}
程序中,Account 类代表一个账户类,该类中有一个声明为 private 的变量 balance,它表示账户余额。可以看到所有对 balance 变量的操作都通过方法来限制,并要按照一定的规则进行修改,而不能直接修改该变量,这就体现了封装性。

测试类最终的输出为“the balance is 31.0”,对余额的修改操作只能通过 deposit() 和 withdraw() 这两个方法进行,这两个方法都对参数进行了校验,从而能确保余额不会被恶意修改。

下面看一下如果不考虑封装性会带来什么问题。假如有人恶意将参数 -10 传入取钱方法 withdraw(),如果没有做好封装后的数据校验则会导致余额增加的严重逻辑错误。
Account account = new Account();
account.withdraw(-10);

此外,如果没有将 balance 变量设置为 private,那么就可以直接随意修改余额,这会导致很严重的问题。
Account account = new Account();
account.balance = 10000;

Java封装的具体实现

如何实现封装性呢?需要通过下面三个步骤来实现。

1) 将需要封装的类属性的访问修饰符改为 private 从而确保属性不能被外部随意访问,比如在下面实例的 Child 类中将 name 和 age 两个属性都设为 private。
public class Child {
    private String name;
    private int age;
}

2) 提供对每个属性访问和修改的方法,通过这些方法能够读取或修改属性值。例如:
public class Child {
    private String name;
    private int age;

    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;
    }
}
在实例程序中,Child 类提供了 getName()、setName()、getAge() 和 setAge() 这 4 个方法来分别访问和修改 name 和 age 这两个属性,我们通常称这些方法为 get() 方法和 set() 方法。

要注意的是,这些方法名并没有规定一定要以 getxxxsetxxx 的形式,而可以根据实际需要进行命名。

3) 对 setxxx 方法添加校验逻辑,从而保证属性的正确性。如果不需要则可以省略这一步。比如下面实例的 setAge() 方法中添加对负数的校验。
public class Child {
    ......
    public void setAge(int age) {
        if (age <= 0) {
                System.out.println("年龄必须为正数");
                return;
        }
        this.age = age;
    }
}

总结

下面罗列了封装的几点好处:

相关文章