Java零基础快速入门|封装

本篇文章主要内容
封装的理解
不封装存在的问题
怎么封装
难点解惑
学习目标
理解为什么要进行封装?封装有什么好处?封装的代码怎么实现?
知识框架

封装的理解
封装是面向对象的三大特征之一,什么是封装?封装有什么好处?怎么封装,代码怎么写?这是大家这一章节要学习的内容。
封装从字面上来理解就是包装的意思,专业点就是信息隐藏,是指利用抽象数据类型将数据和基于数据的操作封装在一起,使其构成一个不可分割的独立实体,数据被保护在抽象数据类型的内部,尽可能地隐藏内部的细节,只保留一些对外接口使之与外部发生联系。系统的其他对象只能通过包裹在数据外面的已经授权的操作来与这个封装的对象进行交流和交互。也就是说用户是无需知道对象内部的细节,但可以通过该对象对外提供的接口来访问该对象。
在现实世界当中我们可以看到很多事物都是封装好的,比如“鼠标”,外部有一个壳,将内部的原件封装起来,至于鼠标内部的细节是什么,我们不需要关心,只需要知道鼠标对外提供了左键、右键、滚动滑轮这三个简单的操作。对于用户来说只要知道左键、右键、滚动滑轮都能完成什么功能就行了。为什么鼠标内部的原件要在外部包装一个“壳”呢,起码内部的原件是安全的,不是吗。再如“数码相机”,外部也有一个壳,将内部复杂的结构包装起来,对外提供简单的按键,这样每个人都可以很快的学会照相了,因为它的按键很简单,另外照相机内部精密的原件也受到了壳儿的保护,不容易坏掉。
根据以上的描述,可以得出封装有什么好处呢?封装之后就形成了独立实体,独立实体可以在不同的环境中重复使用,显然封装可以降低程序的耦合度,提高程序的扩展性,以及重用性或复用性,例如“鼠标”可以在 A 电脑上使用,也可以在 B 电脑上使用。另外封装可以隐藏内部实现细节,站在对象外部是看不到内部复杂结构的,对外只提供了简单的安全的操作入口,所以封装之后,实体更安全了。
不封装存在的问题
我们来看一段代码,在不进行封装的前提下,存在什么问题:


运行结果如下图所示:

以上程序MobilePhone 类未进行封装,其中的电压属性 voltage 对外暴露,在外部程序当中可以对 MobilePhone 对象的电压 voltage 属性进行随意访问,导致了它的不安全,例如手机的正常电压是 3~5V,但是以上程序已经将手机电压设置为100V,这个时候显然是要出问题的, 但这个程序编译以及运行仍然是正常的,没有出现任何问题,这是不对的。
怎么封装
为了保证内部数据的安全,这个时候就需要进行封装了,封装的第一步就是将应该隐藏的数据隐藏起来,起码在外部是无法随意访问这些数据的,怎么隐藏呢?
我们可以使用 java 语言中的 private 修饰符,private 修饰的数据表示私有的,私有的数据只能在本类当中访问。请看程序:


以上程序编译报错了,请看下图:

通过以上的测试,手机对象的电压属性确实受到了保护,在外部程序中无法访问了。但从当前情况来看,voltage 属性有点儿太安全了,一个对象的属性无法被外部程序访问,自然这个数据就没有存在的价值了。所以这个时候就需要进入封装的第二步了:对外提供公开的访问入口,让外部程序统一通过这个入口去访问数据,我们可以在这个入口处设立关卡,进行安全控制,这样对象内部的数据就安全了。
对于“一个”属性来说,我们对外应该提供几个访问入口呢?通常情况下我们访问对象的 某个属性,不外乎读取(get)和修改(set),所以对外提供的访问入口应该有两个,这两个 方法通常被称为set 方法和 get 方法(请注意:set 和get 方法访问的都是某个具体对象的属性, 不同的对象调用get 方法获取的属性值不同,所以set 和 get 方法必须有对象的存在才能调用, 这样的方法定义的时候不能使用static 关键字修饰,被称为实例方法。实例方法必须使用“引用”的方式调用。还记得之前我们接触的方法都是被 static 修饰的,这些方法直接采用“类名” 的方式调用,而不需要创建对象,在这里显然是不行的)。请看以下代码:


运行结果如下图所示:

通过以上程序,可以看出MobilePhone 的 voltage 属性不能在外部程序中随意访问了,只能调用 MobilePhone 的 setVoltage() 方法来修改电压,调用 getVoltage()方法来读取电压,在setVoltage()方法中编写了安全控制代码,当电压低于 3V,或者高于 5V 的时候,程序抛出了异常,不允许修改电压值,程序结束了。只有合法的时候,才允许程序修改电压值。(异常机制在后续的内容中会学到,不要着急。)
总之,在java 语言中封装的步骤应该是这样的:需要被保护的属性使用private 进行修饰, 给这个私有的属性对外提供公开的set 和 get 方法,其中set 方法用来修改属性的值,get 方法用来读取属性的值。并且 set 和 get 方法在命名上也是有规范的,规范中要求 set 方法名是set + 属性名(属性名首字母大写),get 方法名是get + 属性名(属性名首字母大写)。其中set 方法有一个参数,用来给属性赋值,set 方法没有返回值,一般在set 方法内部编写安全控制程序, 因为毕竟set 方法是修改内部数据的,而 get 方法不需要参数,返回值类型是该属性所属类型
(先记住,以后讲:另外set 方法和 get 方法都不带static 关键字,不带static 关键字的方法称为实例方法,这些方法调用的时候需要先创建对象,然后通过“引用”去调用这些方法,实例方法不能直接采用“类名”的方式调用。),例如以下代码:



运行结果如下图所示:

有的读者可能会有这样的疑问:构造方法中已经给属性赋值了,为什么还要提供 set 方法呢?注意了同学们,这是两个完全不同的时刻,构造方法中给属性赋值是在创建对象的时候完成的,当对象创建完毕之后,属性可能还是会被修改的,后期要想修改属性的值,这个时候就必须调用set 方法了。
难点解惑
对于本章节内容来说,比较难以理解的是在之前所写的程序中所有的方法都是带有 static 关键字的,为什么在进行封装时,提供的setter 和getter 方法就不能添加static 关键字了呢?
这块内容在后期学习 static 关键字之后自然就好理解了,这里我简单解释一下:带有 static 关键字的方法是静态方法,不需要创建对象,直接通过“类”来调用。对于没有static 关键字的方法被称为实例方法,这些方法执行时要求必须先创建对象,然后通过“引用”的方式来调用。而对于封装来说,setter 和getter 方法都是访问对象内部的属性,所以setter 和getter 方法在定义时不能添加static 关键字。
小结
通过本章节内容的学习,需要理解为什么要封装,封装有什么好处,以及掌握封装的代码应该如何编写。
最后附Java零基础视频教程给大家,配合学习效果更佳!!

