文档章节

如何创建不可变(Immutable)的Java类或对象

一条大河波浪宽
 一条大河波浪宽
发布于 2013/10/04 18:56
字数 1378
阅读 1.8W
收藏 18

不可变对象(immutable objects),后面文章我将使用immutable objects来代替不可变对象!

那么什么是immutable objects?什么又是mutable Objects呢?

immutable Objects就是那些一旦被创建,它们的状态就不能被改变的Objects,每次对他们的改变都是产生了新的immutable的对象,而mutable Objects就是那些创建后,状态可以被改变的Objects.

举个例子:String和StringBuilder,String是immutable的,每次对于String对象的修改都将产生一个新的String对象,而原来的对象保持不变,而StringBuilder是mutable,因为每次对于它的对象的修改都作用于该对象本身,并没有产生新的对象。

但有的时候String的immutable特性也会引起安全问题,这就是密码应该存放在字符数组中而不是String中的原因!

immutable objects 比传统的mutable对象在多线程应用中更具有优势,它不仅能够保证对象的状态不被改变,而且还可以不使用锁机制就能被其他线程共享。

实际上JDK本身就自带了一些immutable类,比如String,Integer以及其他包装类。为什么说String是immutable的呢?比如:java.lang.String 的trim,uppercase,substring等方法,它们返回的都是新的String对象,而并不是直接修改原来的对象。

如何在Java中写出Immutable的类?

要写出这样的类,需要遵循以下几个原则:

1)immutable对象的状态在创建之后就不能发生改变,任何对它的改变都应该产生一个新的对象。

2)Immutable类的所有的属性都应该是final的。

3)对象必须被正确的创建,比如:对象引用在对象创建过程中不能泄露(leak)。

4)对象应该是final的,以此来限制子类继承父类,以避免子类改变了父类的immutable特性。

5)如果类中包含mutable类对象,那么返回给客户端的时候,返回该对象的一个拷贝,而不是该对象本身(该条可以归为第一条中的一个特例)

当然不完全遵守上面的原则也能够创建immutable的类,比如String的hashcode就不是final的,但它能保证每次调用它的值都是一致的,无论你多少次计算这个值,它都是一致的,因为这些值的是通过计算final的属性得来的!

另外,如果你的Java类中存在很多可选的和强制性的字段,你也可以使用建造者模式来创建一个immutable的类。

下面是一个例子:

public final class Contacts {

    private final String name;
    private final String mobile;

    public Contacts(String name, String mobile) {
        this.name = name;
        this.mobile = mobile;
    }
  
    public String getName(){
        return name;
    }
  
    public String getMobile(){
        return mobile;
    }
}
我们为类添加了final修饰,从而避免因为继承和多态引起的immutable风险。

上面是最简单的一种实现immutable类的方式,可以看到它的所有属性都是final的。

有时候你要实现的immutable类中可能包含mutable的类,比如java.util.Date,尽管你将其设置成了final的,但是它的值还是可以被修改的,为了避免这个问题,我们建议返回给用户该对象的一个拷贝,这也是Java的最佳实践之一。下面是一个创建包含mutable类对象的immutable类的例子:

public final class ImmutableReminder{
    private final Date remindingDate;
  
    public ImmutableReminder (Date remindingDate) {
        if(remindingDate.getTime() < System.currentTimeMillis()){
            throw new IllegalArgumentException("Can not set reminder” +
                        “ for past time: " + remindingDate);
        }
        this.remindingDate = new Date(remindingDate.getTime());
    }
  
    public Date getRemindingDate() {
        return (Date) remindingDate.clone();
    }
}
上面的getRemindingDate()方法可以看到,返回给用户的是类中的remindingDate属性的一个拷贝,这样的话如果别人通过getRemindingDate()方法获得了一个Date对象,然后修改了这个Date对象的值,那么这个值的修改将不会导致ImmutableReminder类对象中remindingDate值的修改。

使用Immutable类的好处:
1)Immutable对象是线程安全的,可以不用被synchronize就在并发环境中共享

2)Immutable对象简化了程序开发,因为它无需使用额外的锁机制就可以在线程间共享

3)Immutable对象提高了程序的性能,因为它减少了synchroinzed的使用

4)Immutable对象是可以被重复使用的,你可以将它们缓存起来重复使用,就像字符串字面量和整型数字一样。你可以使用静态工厂方法来提供类似于valueOf()这样的方法,它可以从缓存中返回一个已经存在的Immutable对象,而不是重新创建一个。

immutable也有一个缺点就是会制造大量垃圾,由于他们不能被重用而且对于它们的使用就是”用“然后”扔“,字符串就是一个典型的例子,它会创造很多的垃圾,给垃圾收集带来很大的麻烦。当然这只是个极端的例子,合理的使用immutable对象会创造很大的价值。


参考:http://javarevisited.blogspot.com/2013/03/how-to-create-immutable-class-object-java-example-tutorial.html

© 著作权归作者所有

一条大河波浪宽

一条大河波浪宽

粉丝 115
博文 27
码字总数 42547
作品 0
海淀
CEO
私信 提问
加载中

评论(7)

slliver
slliver
长知识了~
一条大河波浪宽
一条大河波浪宽 博主

引用来自“sharkbobo”的评论

引用来自“ToB蓝波湾”的评论

引用来自“sharkbobo”的评论

看下Effecitve java,java最佳实践

啥意思?我写的有问题么?

呵呵,没有问题,我本来是想回楼上那个人的,不可变对象最早提出,应该就是在effective java里面,我想让他去看看,0
哦哦 酱紫
james_you
james_you

引用来自“ToB蓝波湾”的评论

引用来自“sharkbobo”的评论

看下Effecitve java,java最佳实践

啥意思?我写的有问题么?

呵呵,没有问题,我本来是想回楼上那个人的,不可变对象最早提出,应该就是在effective java里面,我想让他去看看,0
一条大河波浪宽
一条大河波浪宽 博主

引用来自“sharkbobo”的评论

看下Effecitve java,java最佳实践

啥意思?我写的有问题么?
james_you
james_you
看下Effecitve java,java最佳实践
一条大河波浪宽
一条大河波浪宽 博主

引用来自“铂金小熊”的评论

巧了,我昨天看了篇文章,与你的这個类似。http://dreamhead.blogbus.com/logs/236028457.html

哦,好的,我晚上看下~多谢指点
苗哥
苗哥
巧了,我昨天看了篇文章,与你的这個类似。http://dreamhead.blogbus.com/logs/236028457.html
Java 可变对象和不可变对象

一、简单定义 不可变对象(Immutable Objects)即对象一旦被创建它的状态(对象的数据,也即对象属性值)就不能改变,反之即为可变对象(Mutable Objects)。 不可变对象的类即为不可变类(Immuta...

JackieYeah
2014/03/04
4.2K
0
Java不可变ArrayList

集合类在Java中是引用类型,在操作的时候可能不经意间被程序修改,一些初级开发经常会犯类似的错误。这里我们讨论下如何让ArrayList不可改变。本文将演示以下几种方式: JDK Guava Apache C...

艾贺
2018/09/18
0
0
【翻译】Java中String, StringBuffer, StringBuilder的区别

String 是 Java 中最重要的类之一,并且任何刚开始做Java编程的人,都会用String定义一些内容,然后通过著名的System.out.println()语句来打印出来。 然而,很多Java新手都不会意识到 String...

YuanyuanL
2014/09/03
477
4
Java设计模式之immutable(不可变)模式

immutable简介 不可变对象永远不会发生改变,其字段的值只在构造函数运行时设置一次,其后就不会再改变。例如JDK中常见的两种基本数据类型String和Integer,它们都是不可变对象。为了理解imm...

断桥残雪断桥残雪
2015/08/04
3.2K
1
java并发编程——不可变对象

不可变类 不可变类:指这个类的实例一旦创建完成后,就不能改变其成员变量值。如JDK内部自带的8个包装类和String类都是不可变类(Interger、Long和String等)都是不可变类。所以不可变类并不...

长头发-dawn
2018/10/08
40
0

没有更多内容

加载失败,请刷新页面

加载更多

郑州哪里可以开建筑安装发票-郑州新闻网

郑州哪里可以开建筑安装发票【1.3.2 - 2.9.3.0 - 0.5.6.8.】李生,adb的全称为Android Debug Bridge,是Android手机通用的一个USB端口。百度CarLife的部分车机采用...

识过人石
28分钟前
50
0
垃圾回收算法

四种垃圾回收算法:标记清除算法、标记复制算法、标记整理算法、分代收集算法。 标记清除算法 将需要被回收的对象进行标记,然后回收,缺点是会有很多内存碎片。 标记复制算法 将内存分成两部...

Oaki
48分钟前
71
0
安装npm时,报错rollbackFailedOptional: verb npm-session的解决办法

因为npm没有设置国内镜像服务器(因为大部分内容要去外网下载,直连比较慢) 先执行npm config set registry http://registry.npm.taobao.org 再执行安装命令,如npm install webpack@3.6.0...

copperM
昨天
53
0
第六课:《Linux就该这么学》课堂笔记

“工作马马虎虎,只想在兴趣和游戏中寻觅快活,充其量只能获得一时的快感,绝不能尝到从心底涌出的惊喜和快乐,但来自工作的喜悦并不像糖果那样—放进嘴里就甜味十足,而是需要从苦劳与艰辛中...

宣城热点科技
昨天
75
0
【Go专家编程】go module校验机制详解

go.sum文件中每行数据格式如下: <module> <version>[/go.mod] <hash> github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid ......

恋恋美食
昨天
59
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部