java不可变对象模式,Java并发设计模式--不可变模式(immutable)

本文介绍了Java中创建不可变对象的概念和重要性,包括通过final关键字确保类和属性不可变,以及如何处理可变类型。文章通过示例展示了如何设计不可变类,并指出在处理可变类型如Date时的注意事项。此外,还讨论了不可变对象的优缺点,如减少线程同步开销但可能增加内存消耗,并提出了适用场景,如表示抽象数据类型和在多线程环境中的应用。
摘要由CSDN通过智能技术生成

一、什么是不可变模式?

不可变,顾名思义,就是对象创建之后就不能够变化嘛!更具体地说,就是对象创建之后它的属性值不能够发生变化!所有对原对象的操作都会返回原对象的拷贝。那么在java中怎么做到这一点呢?答案就是使用final关键字。下面我将讲讲如何设计出一个`immutable``对象。

设计一个不可变类应该遵循以下几点:

1、类的所有属性声明为private,去除掉所有的setter方法,防止外界直接对其进行修改

2、类的声明采用final进行修饰,保证没有父类对其修改

3、类的属性声明为final,如果对象类型为可变类型,应对其重新包装,重新new一个对象返回

下面是一个不可变类实例:

package com.wokao66;

/**

* 不可变类

* @author: huangjiawei

* @since: 2018年4月2日

* @version: $Revision$ $Date$ $LastChangedBy$

*

*/

//采用fianl修饰,防止子类继承

public final class Immutable {

/**

* 所有的属性private且final

*/

private final String name;

private final int age;

/**

* 构造方法

* @param name

* @param age

*/

public Immutable(String name, int age) {

this.name = name;

this.age = age;

}

/**

* 去除所有的setter方法

*/

public String getName() {

return name;

}

public int getAge() {

return age;

}

/**

* 将年龄增加10岁

* @param newAge

* @return

*/

public Immutable addAge(int newAge) {

/**

* 重新返回一个对象

*/

return new Immutable(this.getName(), newAge + this.getAge());

}

public static void main(String[] args) {

Immutable immutable = new Immutable("a", 12);

System.err.println(immutable.getAge());

Immutable newImmutable = immutable.addAge(10);

System.err.println(immutable.getAge());

System.err.println(newImmutable.getAge());

}

}

复制代码

运行结果:

12

12

22

复制代码

二、一不小心就设计成可变对象了!

如果上面的不可变类这样设计,那么就变成可变的了!

package com.wokao66;

import java.util.Date;

/**

* 人生处处有惊喜,一不小心就掉进陷阱里

* @author: huangjiawei

* @since: 2018年4月2日

* @version: $Revision$ $Date$ $LastChangedBy$

*/

public final class Mutable {

/**

* 所有的属性private且final

*/

private final String name;

private final int age;

private final Date birthday;

/**

* 构造方法

* @param name

* @param age

*/

public Mutable(String name, int age, Date birthday) {

this.name = name;

this.age = age;

this.birthday = birthday;

}

/**

* 去除所有的setter方法

*/

public String getName() {

return name;

}

public int getAge() {

return age;

}

public Date getBirthday() {

return birthday;

}

/**

* 将年龄增加10岁

* @param newAge

* @return

*/

public Mutable addAge(int newAge) {

/**

* 重新返回一个对象

*/

return new Mutable(this.getName(), newAge + this.getAge(), this.birthday);

}

public static void main(String[] args) {

Date birthday = new Date();

Mutable xiaoming = new Mutable("小明", 21, birthday);

System.err.println("小明的生日为 : " + xiaoming.getBirthday());

//我设置下我的生日,你会发现我的生日居然可以改变

birthday.setTime(System.currentTimeMillis() + 1000000000);

System.err.println("小明的生日为 : " + xiaoming.getBirthday());

}

}

复制代码

输出如下:

小明的生日为 : Mon Apr 02 15:33:44 CST 2018

小明的生日为 : Sat Apr 14 05:20:24 CST 2018

复制代码

可见结果发生了变化,因为Date是可变类型的。将构造方法修改如下:

/**

* 构造方法

* @param name

* @param age

*/

public Mutable(String name, int age, Date birthday) {

this.name = name;

this.age = age;

//对于可变类型的属性,初始化的时候应该重新生成一个

//this.birthday = new Date(birthday.getTime());

this.birthday = birthday;

}

复制代码

输出如下:

小明的生日为 : Mon Apr 02 15:36:24 CST 2018

小明的生日为 : Mon Apr 02 15:36:24 CST 2018

复制代码

二、不可变模式优缺点及应用场景

优点:

1、因为是不可变的,所以不允许程序对其进行修改,避免了程序中修改数据带来的异常产生

2、由于对象是不可变的,减少了线程同步带来的开销

缺点:

1、每次返回都创建新的对象,内存会有一定的开销,不容易被垃圾回收器回收,造成资源的浪费

应用场景:

1、不适合大对象、且创建频繁的场景,因为对象大且创建频繁会容易导致内存泄漏

2、适合表示抽象数据类型(如数字、枚举类型或颜色)的值

3、适合在多线程环境中进行同步而不需要考虑线程同步

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值