创建正真的Java不可变类

时间:2023-03-09 23:26:24
创建正真的Java不可变类

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

 class Name {
private String firstName;
private String lastName; public Name() {
} public Name(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
} public void setFirstName(String firstName) {
this.firstName = firstName;
} public String getFirstName() {
return this.firstName;
} public void setLastName(String lastName) {
this.lastName = lastName;
} public String getLastName() {
return this.lastName;
} public String toString() {
//return getClass().getName() + "@" + Integer.toHexString(hashCode());
return getClass().getName() + "@[firstName=" + this.getFirstName() + ", lastName=" + this.getLastName() + "]";
}
} class Person1 {
private final Name name; public Person1(Name name) {
this.name = name;
} public Name getName() {
return this.name;
} public String toString() {
//return getClass().getName() + "@" + Integer.toHexString(hashCode());
return getClass().getName() + "@[name=" + this.getName() + "]";
}
} class Person {
private final Name name; public Person(Name name) {
// 设置name为临时创建的Name对象,该对象的firstName和lastName与
// 传入的name对象的firstName和lastName相同
this.name = new Name(name.getFirstName(), name.getLastName());
} public Name getName() {
// 返回一个匿名对象,该对象的firstName和lastName与
// 该对象里的name的firstName和lastName相同
return new Name(name.getFirstName(), name.getLastName());
} public String toString() {
//return getClass().getName() + "@" + Integer.toHexString(hashCode());
return getClass().getName() + "@[name=" + this.getName() + "]";
}
} public class PersonNameImmutableTest {
public static void main(String[] args) {
Name n1 = new Name("悟空", "孙");
Person1 p1 = new Person1(n1);
// Person对象的name的firstName值为“悟空”
System.out.println(p1.getName().getFirstName());
// 改变Person对象的name的firstName值
n1.setFirstName("八戒");
// 下面的输出为“八戒”,已经改变了原来的值“悟空”
System.out.println(p1.getName().getFirstName());
// 上面的运行结果说明,Person对象的name的firstName值已经被改变了,
// 这就破坏了设计Person类的初衷 //为了保持Person1对象的不可变性,必须保护好Person1对象的引用类型Field:name,
//让程序无法访问到Person1对象的name Field,也就无法利用name Field的可变性来改变
//Person1对象了。
//为此,我们将Person1类该为Person类使用即可。
Name n = new Name("悟空", "孙");
Person p = new Person(n);
// Person对象的name的firstName值为“悟空”
System.out.println(p.getName().getFirstName());
// 改变Person对象的name的firstName值
n.setFirstName("八戒");
// 这样,无论如何修改name的值,Person对象的name值不会改变,
// 以下输出依然为“悟空”
System.out.println(p.getName().getFirstName());
}
}

或者做如下修改:

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