今天看了这一张模模糊糊的,有点晕。找了几篇播客,终于看懂了。
http://tonylian.iteye.com/blog/391256
http://hi.baidu.com/dongbomoo/blog/item/372cf18a17c4a8789e2fb42d.html
虽然java程序是一门安全的语言(safe language)。但即使在安全语言中,如果不采取一些措施,还是无法使自己与其他的类隔离开。假设类的客户会尽一切手段来破坏这个类的约束条件,在这样的前提下,你必须保护性地设计程序。所以说,从安全的角度考虑,应该设计面对客户的不良行为时仍能保持健壮性的类,无论系统的其它部分发生什么事情,这些类的约束都可以保持为真。
为保护实例的内部信息免受攻击,对构造函数的每个可变参数进行保护性拷贝是必要的。并且使用拷贝之后的对象作为实例的组件,而不使用原始对象。
例如,写了雇员这个类。我自己用的时候对其属性做一些改动稍后会被我的程序提交到后台数据库。但是前端的人员和我做接口的时候,一些查询方法需要雇员对象。但是我不想让他们对这个雇员的属性做修改后也被提交到后台数据库。
所以我可以给他们的对象都是我自己对象的拷贝。他们即使调用这个对象的一些方法改变对象的属性。后面也不会被我的程序提交到后台数据库。
http://topic.csdn.net/u/20080301/20/f0ce18e9-2fc7-4f75-9058-67a8496cc8c7.html
Effective Java》保护性拷贝无非就两条原则:
一、对构造函数的可变参数进行保护性拷贝;
二、对可变域的访问方法,只返回可变域的保护性拷贝(clone)。
什么叫不可变类?如果某个类,当创建了这个类的实例后,就不允许修改它的属性值,那么它就是不可变类。如:java.lang.String 就是一个典型的不可变类创建一个不可变类可按如下步骤:
1.把属性定义为private final类型。
2.不对外公开用于修改属性的setXXX()方法。
3.只对外公开用于读取属性的getXXX()方
以下是对播客例子中的一个修改:
创建一个可变类:Item39_Person
package enhance_chapter7;
public class Item39_Person {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Item39_Person(String name) {
super();
this.name = name;
}
public Item39_Person() {}
}
再创建一个经理类:
package enhance_chapter7;
public class Item39_Manager {
private final Item39_Person person;
public Item39_Person getPerson() {
//return this.person;
//(2)对可变域的访问方法,只返回可变域的保护性拷贝(clone)。
return new Item39_Person(person.getName());
}
public Item39_Manager(Item39_Person person){
//this.person = person;
//(1)保护性拷贝 对构造函数的可变参数进行保护性拷贝
//生成一个新的实例,和Test中的person不是同一个对象,则修改不影响this.person的值
this.person = new Item39_Person(person.getName());
}
@Override
public String toString() {
return "Manager:" + this.person.getName();
}
}
测试:
package enhance_chapter7;
public class Item39_Test {
/**
* @param args
*/
public static void main(String[] args) {
Item39_Person person = new Item39_Person();
person.setName("liangfeng366");
Item39_Manager manager = new Item39_Manager(person);
System.out.println(manager);
//攻击(1)
person.setName("liangfeng");
System.out.println(manager);
//攻击(2)
manager.getPerson().setName("liangfeng");
System.out.println(manager);
}
}
分享到:
相关推荐
3. 使用指针作为函数的参数虽然也能达到与使用引用的效果,但是,在被调函数中同样要给形参分配存储单元,且需要重复使用"* 指针变量名"的形式进行运算,这很容易产生错误且程序的阅读性较差。 四、常引用 如果既...
(3)使用指针作为函数的参数虽然也能达成与使用引用的效果,但是,在被调函数中同样要给形参分派存储单元,且需要反复使用"*指针变量名"的形式进行运算,这很容易产生错误且程序的阅读性较差;另一方面,在主调函数...
(3)使用指针作为函数的参数虽然也能达到与使用引用的效果,但是,在被调函数中同样要给形参分配存储单元,且需要重复使用"*指针变量名"的形式进行运算,这很容易产生错误且程序的阅读性较差;另一方面,在主调函数...
- 在需要进行字符串切割、查找、替换等操作时,可以使用`strpos`, `str_replace`, `explode`等函数。 - 对于数组操作,可以使用`array_filter`, `array_map`, `array_reduce`等函数来简化逻辑。 - **示例代码**:...
(3)使用指针作为函数的参数虽然也能达到与使用引用的效果,但是,在被调函数中同样要给形参分配存储单元,且需要重复使用"*指针变量名"的形式进行运算,这很容易产生错误且程序的阅读性较差;另一方面,在主调...
(3)使用指针作为函数的参数虽然也能达到与使用引用的效果,但是,在被调函数中同样要给形参分配存储单元,且需要重复使用”*指针变量名”的形式进行运算,这很容易产生错误且程序的阅读性较差;另一方面,在主调...
#### 24. **screen** - 屏幕,指显示器或任何显示图像的表面。 - 屏蔽,指阻止某些信号或光线进入的保护措施。 #### 25. **specify** - 指定,指明确指出或定义某个对象的属性或值。 #### 26. **move** - 移动,指...