Java的特性之一——封装
- 封装
- 封装总述
Java的三大特性为:封装、继承和多态。封装作为Java的一大特性,对于提高程序的安全性具有巨大的作用,是防止表示暴露的重要方法之一。在面向对象程式设计方法中,封装(英语:Encapsulation)是指一种将抽象性函数接口的实现细节部分包装、隐藏起来的方法。可以被认为是一个保护屏障,防止该类的代码和数据被外部类定义的代码随机访问。
- 封装的概念
将类的某些信息隐藏在类的内部,不允许外部程序直接访问,而是通过该类提供的方法来对隐藏的信息进行操作和访问。
- 封装的好处
- 只能通过规定的方法访问数据;
- 隐藏类的实例细节,方便修改和实现。
- 封装的实现步骤
- 修改属性的可见属性为private;
- 创建getter和setter方法用于属性的读写:通过这两种方法对数据进行获取和设定,对象通过调用这两种发方法实现对数据的读写;
- 如果需要,在getter和setter方法中加入对属性值合法性的判断。
- 封装的具体实现示例
- 不封装可能出现的问题
首先编写一个Person类,用来表示人这个类,此处我们只为这个类设计姓名和年龄两个成员变量:
这时我们在main方法中就可以创建一个人的对象,并设置这个对象的name和age,如图所示:
这时我们就可以得到这个人的姓名和年龄信息。
但是这时可能会出现一个问题:一般一个人(也就是一个对象)是不会改名的,但是按照我们上面的这种方案,这个对象的名字是可以被任意更改的,如图所示:
我们可以看到,这个对象的名字是可以被用户随意修改的,那么我们这个系统就存在一个巨大的漏洞:我们的类的属性是暴露给用户的,用户可以对对象的属性进行任意的更改。
上面这个漏洞看起来并不致命:有人说一个人本来也有可能改名字啊,那我允许用户修改名字也没有什么问题啊!
那我们在考虑一种情况,比如支付宝:
那按照现在的这一种设计模式,我可以修改这个对象的余额,如下所示:
我们发现我是可以修改这个对象的余额的,这就是一个非常致命的漏洞了,如果阿里支付宝是这么设计的那不就出大问题了!(如果真是这样设计的不就都不用上班了doge),所以我们需要对我们设计的这个类进行封装。
- 按照封装的步骤实现封装
- 首先将类中的成员属性的可见属性更改为private:
更改后我们发现我们在main中是无法直接访问对象的属性了,会报错。
但是这样之后我们怎么设置创建对象的属性呢?
一种方法是使用构造方法,在创建对象时同时对对象初始化,这其中还包含了构造方法的重载的相关知识;还有一种方法就是通过getter和setter方法,通过这两个方法来访问对象的属性。
- 创建getter和setter方法用于属性的读写:
加入getter和setter方法后,我们在main中就需要通过getter和setter方法来访问对象的成员属性,修改为如下代码:
这样用户想要访问我程序对象的成员变量,就必须要通过我类提供的方法才能够访问,而不能用户为所欲为地修改对象的属性,这就是一个非常重要的思想——避免表示暴露。通过这种封装的方法可以提高程序和类的安全性,是非常重要的一种设计方法与理念。
但是封装过后仍然存在一些缺陷,比如没有对用户输入进行合法性检查,在上述程序中,用户可以将年龄设置为负数,如下图所示,但这就出现了一个问题:一个人的年龄怎么可能是负数呢?
想要处理这种情况,我们需要完善我们的封装,在getter和setter中加入输入合法性的判断。
- 加入输入合法性判断:
加入之后就可以处理输入的年龄为负的情况啦。此外还可能有其他不合法的输入情况,如年龄过大或者对于姓名属性的输入不合法,在此处不再展示。
加入输入合法性判断后的程序输出结果:
- 总结
封装是指一种将抽象性函数接口的实现细节部分包装、隐藏起来的方法,将类的某些信息隐藏在类的内部,不允许外部程序直接访问,而是通过该类提供的方法来对隐藏的信息进行操作和访问。可以避免用户直接对对象的属性进行访问和操作,是一种避免表示暴露的重要方法,也是本课程的讲述重点。本篇通过自己思考的具体示例来理解了封装与表示暴露,加深了对课程相关内容的理解。