一、封装简介
1、封装是什么
封装(Encapsulation) 是面向对象编程(OOP)中的一个基本概念,它指的是将对象的状态(数据)和行为(方法)绑定在一起,并对外隐藏对象的内部细节。在Java中,封装通过使用访问修饰符(如 private
、protected
和 public
)来实现,这些修饰符控制类的成员(变量和方法)的可见性和访问级别。封装在Java中确实涉及将类的部分实现细节(包括数据和方法)隐藏起来,只对外暴露必要的抽象接口。
封装可以被视为一种保护屏障,它通过限制外部代码对类内部数据和方法的直接访问,提供了对类的内部实现的保护。要访问该类的代码和数据,必须通过严格的接口控制。封装最主要的功能在于我们能修改自己的实现代码,而不用修改那些调用我们代码的程序片段。适当的封装可以让程式码更容易理解与维护,也加强了程式码的安全性。
打个比较生动的例子就是当我们使用手机时,我们不需要了解其内部电路、处理器、内存或其他硬件组件的具体工作原理。相反,我们只需要使用手机提供的各种功能和应用程序,如拨打电话、发送短信、浏览网页、拍照等。
2、封装的好处
- 提高安全性:通过隐藏内部数据,可以防止外部代码直接操作数据,从而减少错误和提高安全性。
- 简化代码的使用:使用者只需要知道类的公共接口,而不需要了解内部实现细节。
- 易于修改和维护:类的内部实现可以自由修改,而不影响使用该类的其他代码。
二、封装的详细步骤
1. 将属性进行私有化(private)
java
class Person {
private String name;
private int age;
}
2. 提供一个公共的 set
方法,用于对属性判断并赋值
java
class Person {
private String name;
private int age;
public void setName(String name) {
if(name != null && name.length() >= 2 && name.length() <= 6) {
this.name = name;
} else {
throw new IllegalArgumentException("名字长度应当在 2-6 个字");
}
}
public void setAge(int age) {
if(age >= 0 && age <= 200) {
this.age = age;
} else {
throw new IllegalArgumentException("年龄应当在 0-200 之间");
}
}
}
3. 提供一个公共的 get
方法,用于获取属性的值
java
class Person {
private String name;
private int age;
public void setName(String name) {
if(name != null && name.length() >= 2 && name.length() <= 6) {
this.name = name;
} else {
throw new IllegalArgumentException("名字长度应当在 2-6 个字");
}
}
public void setAge(int age) {
if(age >= 0 && age <= 200) {
this.age = age;
} else {
throw new IllegalArgumentException("年龄应当在 0-200 之间");
}
}
public int getAge() {
return age;
}
public String getName() {
return name;
}
}
示例
java
package com.pack1;
public class Encapsulation {
public static void main(String[] args) {
Person person = new Person();
person.setName("张三");
person.setAge(18);
System.out.println("名字:" + person.getName() + "\n年龄:" + person.getAge());
}
}
class Person {
private String name;
private int age;
public void setName(String name) {
if(name != null && name.length() >= 2 && name.length() <= 6) {
this.name = name;
} else {
throw new IllegalArgumentException("名字长度应当在 2-6 个字");
}
}
public void setAge(int age) {
if(age >= 0 && age <= 200) {
this.age = age;
} else {
throw new IllegalArgumentException("年龄应当在 0-200 之间");
}
}
public int getAge() {
return age;
}
public String getName() {
return name;
}
}
运行结果:
可以发现这里我们可以使用 setter 对私有属性进行配置,可以使用 getter 对私有属性进行获取。而不是直接对属性进行访问。
三、补充
1、构造器与 setter 相结合
我们可以在构造器中使用 setter 已保留那些对属性设置的验证逻辑,也就是保留那些防护机制。
java
package com.pack1;
public class Encapsulation {
public static void main(String[] args) {
try {
Person person = new Person("张三",18); // 合法姓名和年龄
System.out.println("姓名: " + person.getName() + "\n年龄" + person.getAge());
// 非法姓名,将引发异常
Person person2 = new Person("",18);
} catch (IllegalArgumentException e) {
System.out.println(e.getMessage());
}
}
}
class Person {
private String name;
private int age;
//使用 setter 的构造器
public Person(String name, int age) {
setName(name);
setAge(age);
}
public void setName(String name) {
if(name != null && name.length() >= 2 && name.length() <= 6) {
this.name = name;
} else {
throw new IllegalArgumentException("名字长度应当在 2-6 个字");
}
}
public void setAge(int age) {
if(age >= 0 && age <= 200) {
this.age = age;
} else {
throw new IllegalArgumentException("年龄应当在 0-200 之间");
}
}
public int getAge() {
return age;
}
public String getName() {
return name;
}
}
运行结果:
可以发现这里使用构造器传入错误的参数依旧会抛出异常,可以发现将构造器与 setter 相结合使用可以保留对参数的验证。