封装是什么,Java封装的具体实现(附带实例)
封装性是面向对象编程的很重要的一种特性,所谓封装就是将内部细节包装起来,从外部看就是一个单一的整体。
对于 Java 而言,封装主要是指将 Java 类中的某些属性隐藏起来,从而防止被外部随意访问和修改,如果要访问则必须通过规定的方法,比如将某个类的属性 data 设置为 private,然后提供 setData() 和 getData() 两个方法来对其进行访问。
举个简单的例子:
测试类最终的输出为“the balance is 31.0”,对余额的修改操作只能通过 deposit() 和 withdraw() 这两个方法进行,这两个方法都对参数进行了校验,从而能确保余额不会被恶意修改。
下面看一下如果不考虑封装性会带来什么问题。假如有人恶意将参数 -10 传入取钱方法 withdraw(),如果没有做好封装后的数据校验则会导致余额增加的严重逻辑错误。
此外,如果没有将 balance 变量设置为 private,那么就可以直接随意修改余额,这会导致很严重的问题。
1) 将需要封装的类属性的访问修饰符改为 private 从而确保属性不能被外部随意访问,比如在下面实例的 Child 类中将 name 和 age 两个属性都设为 private。
2) 提供对每个属性访问和修改的方法,通过这些方法能够读取或修改属性值。例如:
要注意的是,这些方法名并没有规定一定要以
3) 对
对于 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() 方法。
要注意的是,这些方法名并没有规定一定要以
getxxx
和 setxxx
的形式,而可以根据实际需要进行命名。3) 对
setxxx
方法添加校验逻辑,从而保证属性的正确性。如果不需要则可以省略这一步。比如下面实例的 setAge() 方法中添加对负数的校验。
public class Child { ...... public void setAge(int age) { if (age <= 0) { System.out.println("年龄必须为正数"); return; } this.age = age; } }
总结
下面罗列了封装的几点好处:- 封装能减少代码间的耦合性,将各个类都封装好就能减少耦合性;
- 封装能提升数据的安全性,如果我们将属性封装起来就能有效避免属性值被随意修改;
- 封装能控制某些属性为只读或只写,比如只提供 getxxx 方法则为只读;
- 封装能有效提升代码的复用率;
- 封装有利于测试,我们将类封装好后能更方便地进行测试。