首页 > 编程笔记

什么是封装,Java封装的用法详解

在学习封装的概念之前,我们先来了解一下封装的背景,即为什么要有封装。

我们知道类中可以定义属性,用来描述类的静态特征。通过类创建对应的实例化对象,可以对属性进行访问和修改,我们来看下面这个例子,这里定义了一个 User 类,代码如下所示:
public class User {
    public int id;
    public String name;
    public char gender;
    public String password;  
    public void show(){
        System.out.println("用户信息如下:");
        System.out.println("用户编号:"+this.id);
        System.out.println("用户姓名:"+this.name);
        System.out.println("用户性别:"+this.gender);
        System.out.println("用户密码:"+this.password);
    }
}
测试类的 main 方法作为程序的入口,实例化 User 对象并且给属性赋值,同时打印对象信息,代码如下所示:
public class Test {
    public static void main(String[] args) {
        User user = new User();
        user.id = -1;
        user.name = "张三";
        user.gender = '男';
        user.password = "root";
        user.show();
    }
}
程序运行结果如下所示:

用户信息如下:
用户编号:-1
用户姓名:张三
用户性别:男
用户密码:root

从程序的角度来讲,这段代码是没有问题的,但是从现实逻辑来讲是有 bug 的,因为用户编号不可能为负数。因此,我们之前定义类的方式存在一个漏洞,即外部在实例化类对象时,可以随意给对象的属性赋值,只要数据类型一致即可,这样就会存在现实逻辑可能出 bug 的隐患。

那么问题来了,这个隐患怎么解决呢?

我们可以在类中对属性的赋值加以限制,将外部传来的值进行筛选,合格的完成赋值,不合格的加以处理,这个过程就是封装。

所谓封装,指的是将类的属性隐藏在内部,外部不能直接访问和修改,必须通过类提供的方法来完成对属性的访问和修改。封装的核心思想就是尽可能把属性都隐藏在内部,对外提供方法来访问,我们可以在这些方法中添加逻辑处理来实现过滤,以屏蔽错误数据的赋值。

封装的用法

了解完封装的概念,接下来我们学习如何使用封装,分 3 步操作:
  1. 修改属性的访问权限,使得外部不能够直接访问;
  2. 提供外部可以直接调用的方法;
  3. 在方法中加入属性控制逻辑。

修改属性的访问权限,那什么是访问权限?访问权限指的是该属性可以被直接访问的范围,是在属性定义时设定的。在我们之前所写的代码中,属性的访问权限为公有(public),即该属性是公开的,在外部可以直接访问,如下图所示。


图 1 属性的访问权限为公有(public)

现在我们需要将访问权限设置为私有(private),即只能在类的内部访问,外部无法直接访问该属性,将 User 类中所有属性的访问权限改为 private,代码为:
public class User {
    private int id;
    private String name;
    private char gender;
    private String password;  
    //......
}
此时,Test 类中的代码会立即报错,如下图所示。


图 2 私有属性无法访问

第 1 步我们已经完成,现在外部不能直接访问 User 的属性。接下来完成第 2 步,提供外部可以调用的方法,方法同样需要设置访问权限,很显然需要将方法的访问权限设置为 public。同时完成第 3 步,在方法中添加确保属性值正确的逻辑代码,修改完成后的代码为:
public class User {
    //......
    public int getId() {
      return id;
    }
    public void setId(int id) {
      //如果外部传入的id小于0,默认赋值为1
      if(id < 0){
         this.id = 1;
      }else {
         this.id = id;
      }
    }
    //其他属性的getter、setter方法
}
封装完成,每一个属性都添加了两个方法:getter 和 setter,外部通过 getter 获取该属性的值,通过 setter 方法修改该属性的值,Test 的代码会做相应的修改,代码如下所示:
public class Test {
    public static void main(String[] args) {
        User user = new User();
        user.setId(-1);
        user.setName("张三");
        user.setGender('男');
        user.setPassword("root");
        user.show();
    }
}
运行结果为:

用户信息如下:
用户编号:1
用户姓名:张三
用户性别:男
用户密码:root

推荐阅读