首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > 编程 >

打包的漏洞

2012-12-22 
封装的漏洞?我们都知道封装有很多优点,请看如下代码:publicclass Man {privateString nameprivateint age

封装的漏洞

?

我们都知道封装有很多优点,请看如下代码:

publicclass Man {

privateString name;

privateint age;

publicint getAge() {

returnage;

}

publicString getName() {

returnname;

}

publicvoid setAge(int i) {

If(age<=0)

return;

age= i;

}

publicvoid setName(String string) {

name= string;

}

}

?

如果,我们要将name拆分为firstname与lastname,对于访问器的代码,我们可以改写为如下:

public StringgetName() {

return firsstname+" "+lastname;

}

这样,除了改变类的方法外,不会影响其他代码,这样有利于降低程序的耦合性。

还有就是更改器可执行错误检查,不合条件的值可以不予处理。

比如,我们想设置age的值,其值必须大于0。我们可以在setAge方法里面做检查。

???????? 可是难道我们把类的实例域设置为私有的(private),然后提供其访问器与更改器,就真的实现了封装了吗?

???????? 请看如下代码:

public class Order{

privateMan man;

?

publicMan getMan() {

returnman;

}

?

publicvoid setMan(Man man) {

this.man= man;

}

?

}

该类中有个实例变量:引用Man的实例对象一个man。它的访问器方法返回的是一个Man对象。这样做,其实没有起到封装的作用。如:

Ordero=…;

Manman=o.getMan();

man.setName("mark");

System.out.println(o.getMan().getName());//输出mark。

这样就改变了原Order对象中实例域man的状态(一般类都有一组特定的实例域值,这些值的集合就是这个对象的当前状态),man中的name属性由原来的值变为了"mark"。很显然这是一个有漏洞的封装!!!

所以对于这种引用类型的实例域,我们应该改写其访问器方法为:

public Man getMan(){

return (Man)man.clone();

}

此时Man类的代码需要改写为:

?

publicclass Man implements Cloneable{//实现标记接口Cloneable。意味这该Man类可以克隆

privateString name;

privateDate birthday;

privateint age;

?

publicString getName() {

returnname;

}

publicvoid setName(String string) {

name= string;

}

publicMan(String name,Date d,int age) {

this.name= name;

this.birthday=d;

this.age=age;

}

/**

?* 覆盖Object中的clone()方法。

?*/

publicObject clone() throws CloneNotSupportedException {

Man cloned = (Man)super.clone();//浅克隆(不会克隆子对象,子对象需单独克隆)

cloned.birthday=(Date)birthday.clone();//克隆子对象

returncloned;

?

}

publicint getAge() {

returnage;

}

publicDate getBirthday() {

returnbirthday;

}

publicvoid setAge(int i) {

age= i;

}

publicvoid setBirthday(Date date) {

birthday= date;

}

}

?

这样就不会出现上面所说的封装漏洞了。

???????? 这里,顺便说一下final实例域。将实例域定义为final,构建对象时就必须初始化这样的域,也就是说,必须确保在每一个构造器执行之后,这个域的值被设置,且在后面的操作中,不能够再对它进行修改。

???????? final修饰符大都应用于基本数据,或者不可变类的域(如果类中的每个方法都不会改变其对象,这种类就是不可变的类,String类就是一个不可变的类)。对于可变的类,使用final修饰可能会对读者造成混乱。例如,

privatefinal date birthday;

?仅仅意味着存储在birthday变量中的对象引用在对象构造之后不能改变,而并不意味着birthday引用的Date实例对象是一个常量,任何方法都可以对birthday引用的Date对象调用setTime方法改变birthday引用的Date实例对象的状态。

热点排行