创建正真的Java不可变类

如果需要设计一个不可变类,尤其要注意其引用类型Field,如果其引用类型Field的类是可变的,就必须采取必要的措施来保护该Field所引用的对象不会被修改,这样才能创建真正的不可变类。

  1 class Name {
  2     private String firstName;
  3     private String lastName;
  4 
  5     public Name() {        
  6     }
  7 
  8     public Name(String firstName, String lastName) {
  9         this.firstName = firstName;
 10         this.lastName = lastName;
 11     }
 12 
 13     public void setFirstName(String firstName) {
 14         this.firstName = firstName;
 15     }
 16 
 17     public String getFirstName() {
 18         return this.firstName;
 19     }
 20 
 21     public void setLastName(String lastName) {
 22         this.lastName = lastName;
 23     }
 24 
 25     public String getLastName() {
 26         return this.lastName;
 27     }
 28 
 29     public String toString() {
 30         //return getClass().getName() + "@" + Integer.toHexString(hashCode());
 31         return getClass().getName() + "@[firstName=" + this.getFirstName() + ", lastName=" + this.getLastName() + "]";
 32     }
 33 }
 34 
 35 
 36 class Person1 { 
 37     private final Name name;
 38     
 39     public Person1(Name name) {
 40         this.name = name;
 41     }
 42 
 43     public Name getName() {
 44         return this.name;
 45     }
 46 
 47     public String toString() {
 48         //return getClass().getName() + "@" + Integer.toHexString(hashCode());
 49         return getClass().getName() + "@[name=" + this.getName() + "]";
 50     }
 51 }
 52 
 53 class Person { 
 54     private final Name name;
 55     
 56     public Person(Name name) {
 57         // 设置name为临时创建的Name对象,该对象的firstName和lastName与
 58         // 传入的name对象的firstName和lastName相同
 59         this.name = new Name(name.getFirstName(), name.getLastName());
 60     }
 61 
 62     public Name getName() {
 63         // 返回一个匿名对象,该对象的firstName和lastName与
 64         // 该对象里的name的firstName和lastName相同
 65         return new Name(name.getFirstName(), name.getLastName());
 66     }
 67 
 68     public String toString() {
 69         //return getClass().getName() + "@" + Integer.toHexString(hashCode());
 70         return getClass().getName() + "@[name=" + this.getName() + "]";
 71     }
 72 }
 73 
 74 public class PersonNameImmutableTest {
 75     public static void main(String[] args) {
 76         Name n1 = new Name("悟空", "孙");
 77         Person1 p1 = new Person1(n1);
 78         // Person对象的name的firstName值为“悟空”
 79         System.out.println(p1.getName().getFirstName());
 80         // 改变Person对象的name的firstName值
 81         n1.setFirstName("八戒");
 82         // 下面的输出为“八戒”,已经改变了原来的值“悟空”
 83         System.out.println(p1.getName().getFirstName());
 84         // 上面的运行结果说明,Person对象的name的firstName值已经被改变了,
 85         // 这就破坏了设计Person类的初衷
 86 
 87         //为了保持Person1对象的不可变性,必须保护好Person1对象的引用类型Field:name,
 88         //让程序无法访问到Person1对象的name Field,也就无法利用name Field的可变性来改变
 89         //Person1对象了。
 90         //为此,我们将Person1类该为Person类使用即可。
 91         Name n = new Name("悟空", "孙");
 92         Person p = new Person(n);
 93         // Person对象的name的firstName值为“悟空”
 94         System.out.println(p.getName().getFirstName());
 95         // 改变Person对象的name的firstName值
 96         n.setFirstName("八戒");
 97         // 这样,无论如何修改name的值,Person对象的name值不会改变,
 98         // 以下输出依然为“悟空”
 99         System.out.println(p.getName().getFirstName());
100     }
101 }

 

或者做如下修改:

将Name类的setter方法删除掉,这样Name类是不可变的类,Person1类也是不可变的类。

posted @ 2013-12-13 17:56  bluepoint2009  阅读(504)  评论(0编辑  收藏  举报