黑马程序员技术交流社区

标题: 疯狂java讲义中的不可变类设计模式不明白为什么这样,请教 [打印本页]

作者: 涂金哲    时间: 2012-7-2 11:05
标题: 疯狂java讲义中的不可变类设计模式不明白为什么这样,请教
本帖最后由 涂金哲 于 2012-7-4 09:15 编辑

在学习不可变类的设计模式时遇到了一个问题想不明白,向大家求助。
class Person{
private String name;
        private int age;
        public Person(){
        }
        public Person(String name,int age){
                this.name=name;
                this.age=age;
        }
        public void setName(String name){
                this.name=name;
        }
        public String getName(){
                return this.name;
        }
        public void setAge(int age){
                this.age=age;
        }
        public int getAge(){
                return this.age;
        }
}
public class TestImmutable {
        private final Person person;
        public TestImmutable(Person person){
                this.person=person;
        }      
        public Person getPerson()
        {
                return person;
        }
        public static void main(String[] args)
        {
                Person st=new Person("zhangsan",20);
                TestImmutable ti=new TestImmutable(st);
                System.out.println(ti.getPerson().getAge());
                st.setAge(21);
                System.out.println(ti.getPerson().getAge());
        }
}
Final关键字修饰变量表示变量的引用不变,但是对象是可变的。我们通过提供set方法改变对象。若将TestImmutable类改为如下形式则Person类的实例对象将不可改变。

public class TestImmutable {
        private final Person person;
        public TestImmutable(Person person){
                this.person=new Person(person.getName(),person.getAge());//?????
        }
      
        public Person getPerson()
        {
                return new Person(person.getName(),person.getAge());//??????
        }

……
        ……
为什么改为用new创建的对象,就使set方法无法改变属性了呢?在TestImmutable类的构造器中没有直接使用传入的person对象,是用new创建的一个新对象,get方法返回的是一个匿名对象,这样做有什么道理?
作者: Forever。    时间: 2012-7-2 12:27
this.person=new Person(person.getName(),person.getAge());//这段代码明显是将传进来的person对象复制了一边,当然就会出现一个新对象。这样这个新对象是   private final Person person; 这样修饰的所以他本身是改变不了的。而且原来的对象和他已经毫无瓜葛,你再去调用原来的person的set方法和他毫无关系
作者: 周素强    时间: 2012-7-2 14:17
声明:以下分析是经老刘同志的大力支持与讲理后,总结出来的一个思路。如有不对之处(请多指教)属本人意见,与老刘同志无关。

其实这个设计的最终目地是为了不让原对象的属性进行改变。
1,
public class TestImmutable {
        private final Person person;
        public TestImmutable(Person person){
                this.person=person;
        }      
        public Person getPerson()
        {
                return person;
        }
        public static void main(String[] args)
        {
                Person st=new Person("zhangsan",20);
                TestImmutable ti=new TestImmutable(st);
                System.out.println(ti.getPerson().getAge());
                st.setAge(21);
                System.out.println(ti.getPerson().getAge());
        }
}
首先以上代码不可完成其属性不可变的目地,原因在于final修饰的person引用变量与main方法中st引用变量同时指向的是同一个对象,当其用get方法返回的对象对属性进行修改后,对象本身的属性将会更改不管是用哪个引用变量来get属性都是得到修改后的值。

2,
public class TestImmutable {
        private final Person person;
        public TestImmutable(Person person){
                this.person=new Person(person.getName(),person.getAge());//?????
        }
      
        public Person getPerson()
        {
                return new Person(person.getName(),person.getAge());//??????
        }
如果使用上方代码来操作的话,那么final所修饰的person引用变量与main方法中的st引用变量不是指向同一个对象,其实上方的get方法得到的person对象简单点说是克隆出一个person对象,所以在对这个对象进行set属性时,原st引用的对象属性始终是没有改变的。

3,
3.1一般要保证类不变,就把类加final,不能被继承
3.2保证方法不变,也是final,不能被覆盖
3.3保证对象不变,也是final,但不能保证属性不变(至于属性不变,就是刚才那种方法来进行设计)
作者: 葛奎    时间: 2012-7-2 15:38
public class TestImmutable {
        private final Person person;
        public TestImmutable(Person person){
                this.person=new Person(person.getName(),person.getAge());//构造器代码:又重新创建了一个对象

        }
      
        public Person getPerson()
        {
                return new Person(person.getName(),person.getAge());//而这里面又一次重新创建了一个对象
        }
public static void main(String[] args)
        {
                Person st=new Person("zhangsan",20);//此处创建了一个Person对象
                TestImmutable ti=new TestImmutable(st);//当创建TestImmutable对象的时候会调用构造器
                System.out.println(ti.getPerson().getAge());//这里面又创建了一个对象
                st.setAge(21);//当调用setAge()函数的时候,传入21,是st中的对象属性修改了。与t1.getPerson()已经没有关系了
                System.out.println(ti.getPerson().getAge());
        }



作者: 涂金哲    时间: 2012-7-4 09:23
Forever。 发表于 2012-7-2 12:27
this.person=new Person(person.getName(),person.getAge());//这段代码明显是将传进来的person对象复制了 ...

非常感谢您的帮助
作者: 涂金哲    时间: 2012-7-4 09:24
周素强 发表于 2012-7-2 14:17
声明:以下分析是经老刘同志的大力支持与讲理后,总结出来的一个思路。如有不对之处(请多指教)属本人意见 ...

非常感谢 很详细
作者: 涂金哲    时间: 2012-7-4 09:25
葛奎 发表于 2012-7-2 15:38
public class TestImmutable {
        private final Person person;
        public TestImmutable(Perso ...

明白了 谢谢……




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2