暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

什么是封装?

理想二旬不止 2021-09-13
582

为满足移动端和PC端的双重阅读体验,以及文章质量的保证,开始重构的以及新写的文章都会基于 “语雀” 平台编写,公众号会同步刚发布的文章,但随后的修改或者更新只会在语雀中维护。

👉 点击底部左下角 “阅读原文” 即可跳转到文章最新页面!
理想二旬不止@BWH_Steven

其实在我们面向对象这一阶段的学习中,我们就是围绕Java的三大特性(封装、继承、多态)以及封装抽象等等知识来讲解的,可以毫不怀疑的说,在我看来,理解这些概念的重要性,远大于各种方法函数的调用。无论后面接触到各种复杂的程序,无论用了多么巧妙的设计思想,什么样的设计模式,什么样的框架,其背后都有面向对象相关的几个概念的影子。

要记住,这部分是基础,而非技术,如果想成为一名优秀的开发者,那么就要对其熟练掌握,灵活运用。

1. 什么是封装

封装是指隐藏对象的属性和实现细节,仅对外提供公共访问方式。简单的来说就是我将不想给别人看的数据,以及别人无需知道的内部细节, “锁起来” ,我们只留下一些入口,使其与外部发生联系。
那我们如何给我们的数据 “上锁” 呢?
我们使用,public、private、protected 等权限修饰符 在类的内部设定了边界,这些不同程度的 ”锁“ 决定了紧跟其后被定义的东西能够被谁使用。

2. 封装的好处

隐藏实现细节,提供公共的访问方式,提高了代码的复用性,提高安全性

2.1 隐藏实现细节,提供公共的访问方式

2.1.1 隐藏实现细节怎么理解呢?

我们将一些功能封装到类中,而客户端的程序员,不需要知道类中的这个方法的逻辑原理,类程序员只需要给他一个对外的接口,客户端程序员只需要能够调用这个方法即可,
例如:夏天宿舍很热,我们(用户)只需要操作遥控器即可使用空调,并不需要了解空调内部是如何运行的

2.1.2 提供公共的访问方式又怎么理解呢?

我们先来看一段标准案例

public class Student {
    //定义成私有成员变量(private)
    private String name;
    private int age;

    //无参构造
    public Student() {
        super();
    }

    //带参构造
    public Student(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }

    //成员变量的set和get方法(与外界联系的桥梁)
    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public int getAge() {
        return age;
    }
}
public class StudentTest {
    public static void main(String[] args) {
        //创建学生类对象 s
        Student s = new Student();

        //对象s调用类中的公共方法setName()和setAge()
        //set方法给成员变量赋值
        s.setName("BWH_Steven");
        s.setAge(20);

        //get方法获取成员变量
        System.out.println(s.getName() + s.getAge());
    }
}

我们可以看到在上面的案例中,成员变量都使用 private 修饰,而下面的 get 和 set 方法均使用了public修饰,其实被private修饰的属性就是我们想要锁起来的数据,而 set、get 方法就是我们打开这把锁的钥匙

被private所修饰的内容是,除类型创建者和类型的内部方法之外的任何人都不能访问的元素,所以我们这些数据就被我们通过private “锁” 了起来,而我们外界是可以通过创建对象来调用一个类中的公共方法的,所以被 public修饰的 set 和 get 方法外界所能访问的,而这两个方法又可以直接访问我们的私有成员变量,所以 set 和 get 方法就成为了私有成员与外界沟通的钥匙。

2.2 提高了代码的复用性

功能被封装成了类,通过基类与派生类之间的一些机制(组合和继承),来提高代码的复用性

2.3 提高安全性(此处待修改)

关于安全性的问题,我们先看一种说法:

public class Student {

    private String name;
    private int age;

    public Student() {
        super();
    }

    public Student(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    //在setAge()方法中加入了校验的内容
    //不合法数据是不允许传递给成员变量的
    public void setAge(int age) {
        if (age < 0 || age > 120) {
            System.out.println("Error");
        }else {
            this.age = age;
        }     
    }

    public int getAge() {
        return age;
    }
}
public class StudentTest {
    public static void main(String[] args) {
        Student s = new Student();
        System.out.println(s.getName() + s.getAge());

        //错误的方式!!!
        s.name = "BWH_Steven";
        s.age = 20;
        System.out.println(s.getName() + s.getAge());

           //正确的方式!!!
        s.setName("BWH_Steven");
        s.setAge(20);
    }
}

我们用private来修饰我们的成员变量不是没有任何依据的,如果我们的成员变量修饰符改为public,这句意味着外界可以使用对象直接访问,修改这个成员变量,这可能会造成一些重大的问题。

例如:外界通过对象去给成员变量赋值,可以赋值一些非法的数据,这明显是不合理的。所以在赋值之前应该先对数据进行判断。StudenTest 是一个测试类,测试类一般只创建对象,调用方法,所以这个判断应该定义在Student类中。需要使用逻辑语句,而逻辑语句应该定义在方法中。所以在Student类中提供一个方法来对数据进行校验但是如果偏偏不调用方法来赋值,还是通过 对象名.变量
直接赋值,这样我们的方法内的逻辑就没有起作用所以我们必须强制要求使用我的方法,而不能直接调用成员变量这也正是我们使用 private 修饰成员变量的原因!

3. 补充

上述举例为 JavaBean 类,一般很少在 set get 中去添加一些逻辑,一般都是一种简单的赋值,而且诸多框架和不错的项目均使用了这种规范方法。
大家可能会觉得 JavaBean 这个例子不是特别恰当,但是大家重点去理解这种感觉,因为封装并不只有 JavaBean,很多去重复,提供复用的场合都有它的身影。

🔥️ 语雀地址:

  • https://www.yuque.com/ideal-20

🔥️ 本篇语雀地址:

  • https://www.yuque.com/ideal-20/java/vgk5c6

🔥️ 或者点击左下角 “阅读原文”

文章转载自理想二旬不止,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论