创建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对象会创造很大的价值。
创建immutable类的更多相关文章
- Java中如何创建不可变(immutable)类
什么是不可变类 1. 不可变类是指类的实例一经创建完成,这个实例的内容就不会改变. 2. Java中的String和八个基本类型的包装类(Integer, Short, Byte, Long, Dou ...
- 使用MyBatis的Generator自动创建实体类和dao的接口与xml
在实际的项目中其实建立数据库和设计数据库的时候特别重要,而等数据库设计完成之后,根据数据库创建实体类的工作就特别麻烦和繁琐了,不仅很麻烦,而且很浪费时间,不做又不行,这次就找到了一个简单的方法可以让m ...
- 为什么 String 是 immutable 类
二哥,你能给我说说为什么 String 是 immutable 类(不可变对象)吗?我想研究它,想知道为什么它就不可变了,这种强烈的愿望就像想研究浩瀚的星空一样.但无奈自身功力有限,始终觉得雾里看花终 ...
- vs里根据json快速创建对应类的方法
有时候,我们在调用别人接口的时候,服务端返回了一个json格式的字符串,我们要获取json里面的数据的话一般有两种方式: 1.通过正则 2.反序列化成一个对象 第一种方式这里不再多说,主要说一下第二种 ...
- [转]自己写PHP扩展之创建一个类
原文:http://www.imsiren.com/archives/572 比如我们要创建一个类..PHP代码如下 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 ...
- C#-数据库访问技术 ado.net——创建 数据库连接类 与 数据库操作方法 以及简单的数据的添加、删除、修改、查看
数据库访问技术 ado.net 将数据库中的数据,提取到内存中,展示给用户看还可以将内存中的数据写入数据库中去 并不是唯一的数据库访问技术,但是它是最底层的数据库访问技术 1.创建数据库,并设置主外键 ...
- classmethod一个用处是创建可选类构造器
Definition and Introduction通常来说, descriptor 是一种绑定着特殊行为属性的对象, 在访问它时行为被descriptor协议定义的方法所重载.这些方法是__get ...
- MFC编程入门之八(对话框:创建对话框类和添加控件变量)
创建好对话框资源后要做的就是生成对话框类了.生成对话框类主要包括新建对话框类.添加控件变量和控件的消息处理函数. 例程Addition是基于对话框的程序,所以程序自动创建了对话框模板IDD_ADDIT ...
- (spring-第17回【AOP基础篇】) 创建增强类
一. 增强类包含的信息: a) 横切逻辑(插入的具体代码) b) 部分连接点信息(在方法的哪个位置插入代码,比如方法前.方法后等). 二. 增强的类型 每一种增强有一个需要实现的增强类 ...
随机推荐
- js/jsp清空表单2种方法
js方式清空表单数据的两种方式 方法1:遍历页面元素 /* 清空FORM表单内容 id:表单ID*/ function ClearForm(id) { var objId = docume ...
- ✡ leetcode 160. Intersection of Two Linked Lists 求两个链表的起始重复位置 --------- java
Write a program to find the node at which the intersection of two singly linked lists begins. For ex ...
- [转]ssh常用用法小结
ssh常用用法小结 1.连接到远程主机: 命令格式 : ssh name@remoteserver 或者 ssh remoteserver -l name 说明:以上两种方式都可以远程登录到远程主机, ...
- Draw a Border around any C# Winform Control
public class MyGroupBox : GroupBox { protected override void OnPaint(PaintEventArgs e) { base.OnPain ...
- eclipse adt 项目依赖,使用git上的项目
从git下载的android工程不能直接导入eclipse,有的项目要依赖这个项目,怎么办呢 好像只能新建一个android项目,然后把libs,res,src,AndroidManifest.xml ...
- Unix Linux 编程书籍
UNIX环境高级编程(第3版) Advanced Programming in the UNIX Environment Linux/UNIX系统编程手册 Linux/UNIX系统编程手册 (豆瓣) ...
- ctf之加密
from:http://drops.wooyun.org/tips/10002 0x01 Base64 Base64:ZXZhbCgkX1BPU1RbcDRuOV96MV96aDNuOV9qMXVfU ...
- 取得某个数组前key大 PHP实现
<?php function max_key($arr, $key) { $tmp_key = $key; $max_arr = array(); while($tmp_key--) $max_ ...
- nginx基于域名的虚拟主机 反向代理配置实例
vi /etc/nginx/conf.d/safeadmin.xxx.com.conf: server { listen 80; server_name safeadmin.xxxx.com; loc ...
- linux apache httpd安装(安装全部modules)
一.安装apache(http服务) 1. 从apache.org下载源码安装包 2. 解压缩# tar zxf httpd-2.2.4.tar.gz# cd httpd-2.2.4 3. 安装apa ...