创建immutable类

不可变对象(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对象会创造很大的价值。

时间: 2024-08-09 06:35:03

创建immutable类的相关文章

使用MyBatis的Generator自动创建实体类和dao的接口与xml

在实际的项目中其实建立数据库和设计数据库的时候特别重要,而等数据库设计完成之后,根据数据库创建实体类的工作就特别麻烦和繁琐了,不仅很麻烦,而且很浪费时间,不做又不行,这次就找到了一个简单的方法可以让myBatis帮你完成这件事情. 首先你需要一个Generator的myeclipes的插件,这个插件能在网上找到,安装方法也很简单就多说了. 下载了这个插件之后,新建一个xml,这个配置文件,就是对你所需要的实体类dao和xml进行合理的配置,看看你需要那些,不需要那些. 这里的配置我参考了网上给出

创建多线程类

# -*- coding: cp936 -*- #python 27 #xiaodeng #http://www.cnblogs.com/fnng/p/3489321.html #创建多线程类 import threading from time import sleep,ctime class MyThread(threading.Thread):#threading.Thread '创建MyThread类,用于继承threading.Thread类.' def __init__(self,f

如何:从代码创建 UML 类图(ZZ)

您拖动的一个或多个类将显示在关系图上. 它们依赖的类将显示在"UML 模型资源管理器"中. 参见 模型表示类型的方式. 将程序代码中的类添加到 UML 模型 打开一个 C# 项目. 将一个 UML 类图.解决方案: 在"体系结构"菜单上,选择"新建关系图". 在"添加新关系图"对话框中选择"UML 类图". 如果您还没有,将建模项目创建. 打开"体系结构资源管理器": 在"体系

创造自己的群集类型----之----创建“包装”类以封装预定义集群类型

第一步:创建"包装"类以封装预定义集群类型 public class EncapsulatePredefinedCluster { private ArrayList students; public EncapsulatePredefinedCluster() { students = new ArrayList(5); } /// <summary> /// 注册新生 /// </summary> /// <param name="s&quo

创建一个类

c++是一门面向对象的编程语言,而面向对象的基础就是类 使用C++创建一个Student类 class Student//学生类 { private://私有 //数据成员 char Name[10];//姓名 int Age;//年龄 int No;//学号 public://公有 //成员函数 //输入学生的信息 void InputStudent(char *name, int age, int no) { strcpy(Name, name); Age = age; No = no; }

利用MyEclipse自动创建PO类、hbm文件(映射文件)、DAO

前提条件:表sjzdfl  表sjzdxx (使用数据库MySQL) 表sjzdfl (两个字段sjzdflId 和 sjzdflmc) 表sjzdfl 建表语句: [sql] view plaincopy DROP TABLE IF EXISTS `sjzdfl`; CREATE TABLE `sjzdfl` ( `sjzdflId` int(11) NOT NULL auto_increment, `sjzdflmc` varchar(255) default NULL, PRIMARY K

【转】VS2010/MFC编程入门之八(对话框:创建对话框类和添加控件变量)

原文网址:http://www.jizhuomi.com/software/153.html 前两讲中鸡啄米为大家讲解了如何创建对话框资源.创建好对话框资源后要做的就是生成对话框类了.鸡啄米再声明下,生成对话框类主要包括新建对话框类.添加控件变量和控件的消息处理函数等. 因为鸡啄米给大家的例程Addition是基于对话框的程序,所以程序自动创建了对话框模板IDD_ADDITION_DIALOG,并自动生成了对话框类CAdditionDlg,它是从CDialogEx类派生的.大家用过VC++6.0

vs里根据json快速创建对应类的方法

有时候,我们在调用别人接口的时候,服务端返回了一个json格式的字符串,我们要获取json里面的数据的话一般有两种方式: 1.通过正则 2.反序列化成一个对象 第一种方式这里不再多说,主要说一下第二种,(为什么呢,你看到后面 你也会喜欢上第二种) 有人肯定会说, json字符串万一很长,很复杂,我一个个去写类????有这个功夫 我用个正则 程序都已经写完了,你还在写对应的类. 是的,我之前也是通过正则的方式获取想要的数据,因为第二种方式,我们创建与json相对应的类的话 如果json很复杂,那是

使用JBoss Tool反向创建PO类

使用Hibernate Tool可以根据已有的数据库结构,反向创建PO.DAO等类,方便于开发,最近正好有个工作内容,需要用这个,所以重新捡起来学习下. 现在Hibernate Tool已经被JBoss收购,起了个新名字,叫做JBoss Tool,高大上的名字. 要求jdk6或7的版本,并且要求Eclipse Luna 4.4.2版本. 在Edit Configuration中选择已有的一个工程(可以是普通的java工程,也可以是maven工程),然后可以选择Database connectio