Java中的不变对象

zjun Lv4

在开发过程中,我们经常会遇到“不可变对象”的需求,所谓不可变对象(Immutable Object),顾名思义就是:对象一旦被创建后,对象所有的状态及属性在其生命周期内不会发生任何变化。
比如业务中有一个关于员工的定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public class Employee{
private String SN; // 员工号
private String name; // 员工姓名
private Date birthday; // 员工生日

public Employee(String SN, String name, Date birthday){
this.SN = SN;
this.name = name;
this.birthday = birthday;
}

public String getSN(){
return SN;
}

public String getName(){
return name;
}

public Date getBirthday(){
return birthday;
}

public static void main(String[] args) throws InterruptedException {
Date birth = new Date();
Employee emp = new Employee("123", "John", birth);
System.out.println(emp.getBirthday());
Thread.sleep(1000);
birth.setTime(System.currentTimeMillis());
System.out.println(emp.getBirthday());
Thread.sleep(1000);
birth.setTime(System.currentTimeMillis());
System.out.println(emp.getBirthday());
}
}

运行结果:

1
2
3
Wed Aug 08 21:03:37 CST 2018
Wed Aug 08 21:03:38 CST 2018
Wed Aug 08 21:03:39 CST 2018

通常遵照以下几点来定义不可变对象:

  • 所有成员变量必须是private
  • 最好同时用final修饰(非必须)
  • 不提供能够修改原有对象状态的方法
    • 最常见的方式是不提供setter方法
    • 如果提供修改方法,需要新创建一个对象,并在新创建的对象上进行修改
  • 通过构造器初始化所有成员变量,引用类型的成员变量必须进行深拷贝(deep copy)
  • getter方法不能对外泄露this引用以及成员变量的引用
  • 最好不允许类被继承(非必须)

上面Employee类中的birthday属性,传入和传出的都是Date对象的引用,所以依然可以在类的外部通过引用对birthday的值进行修改。所以不可变类应该改成下面的样子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public class Employee{
private String SN; // 员工号
private String name; // 员工姓名
private Date birthday; // 员工生日

public Employee(String SN, String name, Date birthday){
this.SN = SN;
this.name = name;
//创建birthday的一个私有拷贝,
//保护这个属性不受调用者对于原始birthday对象所做任何改变的影响
this.birthday = (Date) birthday.clone();
}

public String getSN(){
return SN;
}

public String getName(){
return name;
}
//返回一个可变对象的一个保护性拷贝.调用者可以任意改变返回的Date对象,而不会影响类的内部.
public Date getBirthday(){
return(Date) birthday.clone();
}

public static void main(String[] args) throws InterruptedException {
Date birth = new Date();
Employee emp = new Employee("123", "John", birth);
System.out.println(emp.getBirthday());
Thread.sleep(1000);
birth.setTime(System.currentTimeMillis());
System.out.println(emp.getBirthday());
Thread.sleep(1000);
birth.setTime(System.currentTimeMillis());
System.out.println(emp.getBirthday());
}
}

运行结果:

1
2
3
Wed Aug 08 21:05:37 CST 2018
Wed Aug 08 21:05:37 CST 2018
Wed Aug 08 21:05:37 CST 2018

注:如果类中存在集合对象,可以通过JDK或Guava提供的方法创建不可变集合

  • Collections.unmodifiableList(List<? extends T> list)
  • ImmutableList.copyOf(list)
  • 标题: Java中的不变对象
  • 作者: zjun
  • 创建于 : 2018-08-08 21:56:22
  • 更新于 : 2023-12-05 21:29:01
  • 链接: https://zjun.site/2018/08/998e535db3d2.html
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论
此页目录
Java中的不变对象