5.3 封装性

封装性是面向对象的第一大特性,所谓的封装性就是指对外部不可见,下面通过一个不封装的代码来观察所存在的问题。

【例5.7】观察以下程序的问题

程序执行结果:

由上面的程序可以发现,在程序中将年龄(age)赋值为-30岁,这在程序中是不会有任何问题的,因为int可以取负值,但对于用户这明显是一个不合法的数据,因为没有一个人的年龄会是-30岁,所以最终程序在调用tell()方法的时候才会打印出了这种错误的信息。这就好比要加工一件产品一样,本身加工的原料就有问题,那么最终加工出来的产品也一定是一个不合格的产品。而只有在原料的入口处进行严格的把关,才有可能避免此类问题。

读者可以发现,之前所列举的程序都是用对象直接访问类中的属性,这在面向对象法则中是不允许的。所以为了避免程序中这种错误的情况的发生,在一般的开发中往往要将类中的属性封装(private),封装的格式如下:

【格式5-4 使用封装性】

【例5.8】为程序加上封装性

程序编译结果:

上面的程序在定义属性时使用了private关键字定义,而加入此关键字之后发现程序无法编译了,所提示的错误为:“属性(name、age)为私有的”,所以不能由对象直接进行访问。这样就可以保证对象无法直接去访问类中的属性,从而保证对入口处有所限制,但是这样一来该如何访问此属性呢?为了解决属性必须封装且又必须访问的矛盾,在Java开发中对于私有属性的访问有了以下的明确定义:“只要是被封装的属性,则必须通过setter和getter方法设置和取得”。

提示

进一步深入。

对于私有属性要使用setter和getter方法设置和访问实际上还有一个原因,就是在Java中存在反射机制,在各个程序中,反射机制都会利用setter和getter设置和取得属性内容,关于反射机制可以参考第3部分的内容讲解。

【例5.9】为前面类中的私有属性加上setter和getter方法

程序执行结果:

先暂时不去考虑程序的运行结果,先观察程序的结构,在程序中可以发现通过setter()和getter()方法可以设置和取得属性,而在主方法调用时,也是调用了setter()方法进行内容的赋值,也就是说如果想对设置进去的值进行检查的话,则只需要在setter()方法处检查即可。

【例5.10】在setter()方法处加上检测代码

程序执行结果:

从程序运行结果可以发现,因为程序中在setter()方法处加入验证代码,所以如果设置的年龄数值不正确的话,则不会把值赋给age属性,所以程序运行结果处出现的年龄为“0”。

提示

关于private的补充说明。

1.在以后的开发中读者一定要记住:类中全部属性都必须封装,封装之后的属性必须通过setter和getter进行访问。

2.面向对象的封装性本身并不是单指private关键字,为了让读者可以更快的理解封装性,所以本章只是暂时将封装性的概念进行简单的讲解,读者必须记住用private声明的属性或方法只能在其类的内部被调用,而不能在类的外部被调用。

3.读者可以发现在此处类中已经有很多的方法,正常情况下,类中的方法直接写上方法名称就可以完成本类中的方法调用,如果在此时非要强调是本类中的方法,也可以在调用的时候按“this.方法名称()”的形式编写:

在代码之中是否使用this明确的表示当前类中的方法并没有严格的要求,但是笔者在这里建议读者在编写代码的时候最好采用this.方法的形式,这样会比较标准一些,在查错的时候也会更加方便。

程序中的属性进行封装之后,在使用类图表示封装属性的时候就必须按照如下的风格:

“-属性名称:数据类型”。

上面程序的类图结构如图5-8所示。

图5-8 类图表示

提示

“-”表示private。

在图5-8中,可以发现name属性前加上了“-”,实际上这表示的是private。