浏览 2307 次
锁定老帖子 主题:不可变对象,深层次克隆等总结
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2009-01-13
最后修改:2009-01-13
不可变对象的几个基本原则: 1.class要声明为final 2.所有属性都声明为private访问权限 3.只提供get方法,不提供set方法 4.提供构造方法,并且在构造方法中初始化所有你想初始化的数据 5.类中有组合情况发生时,从get方法得到组合对象之前,先克隆这个对象。 6.组合对象传递给构造函数的时候,也要先克隆一份。 1.一般不可变类是这样的: public final class Example { private String userName; private String password; public Example(String userName,String password) { this.userName = userName; this.password = password; } public String getPassword() { return password; } public String getUserName() { return userName; } } 原理如下: 声明为final,以防它被子类继承修改,所以参数都是private,不能直接访问,而只能通过get访问,但是没有set方法,所以不能设定值,而值的设定是在构造器中设置的,这样就形成了不可变的类。它的属性都是String或者可以是一些基本类型,不需要克隆,而String本身就是final修饰的类,也是恒定的。这些都是很容易想到的。 现在扩展一下,类中需要组合另一个对象,也就是说,不光只有基本类型了,还有引用类型。下面是复杂一些的情况 这是另一个类,他要被组合到Example中 public class Address { private String homeAddr; private String mail; private int code; public Address(String homeAddr, String mail, int code) { super(); this.homeAddr = homeAddr; this.mail = mail; this.code = code; } //以下是get/set,省略.... } 现在修改Example为Example1,加入了Address类的组合。 public class Example1 { private String userName; private String password; private Address address; public Example1(String userName,String password,Address address) { this.userName = userName; this.password = password; this.address = address; } public String getPassword() { return password; } public String getUserName() { return userName; } public Address getAddress() { return address; } } 现在这个类,貌似符合了不可变类的原则(1-4条),现在来测试一下。 public class TestExample1 { public static void main(String[] args) { // 先填充Address对象 Address address = new Address("大拐弯幼儿园", "daguanwai.com", 1); // 填充Example1 Example1 e1 = new Example1("王小黑", "123", address); Address temp = e1.getAddress(); System.out.println("王小黑上的幼儿园名字是: " + temp.getHomeAddr()); // 修改address address.setHomeAddr("大黄豆劳改所"); System.out.println("王小黑上的幼儿园名字是: " + temp.getHomeAddr()); } } 打印结果: 王小黑上的幼儿园名字是: 大拐弯幼儿园 王小黑上的幼儿园名字是: 大黄豆劳改所 还是发生了改变,没达到不可变类的目的。 2.java总是按值传递的,引用的值就是地址,前面的blog已经说过(http://doubleeo.iteye.com/admin/blogs/310082),所以现在共享的是同一个address ,对address的修改,都会体现在Example1 上面,为了达到不可变类的效果,要用克隆。 所以Example1修改成如下这样 public class Example1 { private String userName; private String password; private Address address; public Example1(String userName,String password,Address address) { this.userName = userName; this.password = password; this.address = (Address)address.clone(); } public String getPassword() { return password; } public String getUserName() { return userName; } public Address getAddress() { return (Address)address.clone(); } } 当然Address给重写clone方法 public class Address implements Cloneable { private String homeAddr; private String mail; private int code; //构造方法及get/set省略... @Override protected Object clone() { try { return super.clone(); } catch (Exception e) { throw new InternalError(); } } } 再测试一下Example1 打印结果: 王小黑上的幼儿园名字是: 大拐弯幼儿园 王小黑上的幼儿园名字是: 大拐弯幼儿园 这次正确了,把example1塑造为不可变的了。 以上的克隆叫浅克隆(Shallow Cloning) 3.再近一步复杂,Example1中还是组合,但是这次组合的是容器,像List这种,用来装对象引用的容器,如果你还按刚才那种clone方法,肯定是达不到目的了,虽然List本身的引用克隆了一个新的,但是里面包裹着的对象的引用,还是那一份,所有改变它还是会破坏不可变类,因此要用到深层克隆(Deep Cloning) 修改后的版本如下 public class Example1 { private String userName; private String password; private List<Address> address; public Example1(String userName,String password,List<Address> address) { this.userName = userName; this.password = password; this.address = cloneAddress(address); } public String getPassword() { return password; } public String getUserName() { return userName; } public List<Address> getAddress() { return cloneAddress(address); } //深层次clone方法 private List<Address> cloneAddress(List<Address> address){ int size = address.size(); List<Address> newList = new ArrayList<Address>(size); for(Address addr:address) newList.add((Address)addr.clone()); return newList; } } 也就是说,要把容器中的每个引用再一次克隆,如果引用是一个List,那么就要再把这个List中的所有引用再克隆。 最后再总结一下: 1.class要声明为final 2.所有属性都声明为private访问权限 3.只提供get方法,不提供set方法 4.提供构造方法,并且在构造方法中初始化所有你想初始化的数据 5.类中有组合情况发生时,从get方法得到组合对象之前,先克隆这个对象。 6.组合对象传递给构造函数的时候,也要先克隆一份。 7.如果浅克隆不能符合不可变对象的正常行为,就要实现深层克隆 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |