如何在Java中写出Immutable的类?java
要写出这样的类,须要遵循如下几个原则:缓存
1)immutable对象的状态在建立以后就不能发生改变,任何对它的改变都应该产生一个新的对象。安全
2)Immutable类的全部的属性都应该是final的。并发
3)对象必须被正确的建立,好比:对象引用在对象建立过程当中不能泄露(leak)。性能
4)对象应该是final的,以此来限制子类继承父类,以免子类改变了父类的immutable特性。this
5)若是类中包含mutable类对象,那么返回给客户端的时候,返回该对象的一个拷贝,而不是该对象自己(该条能够归为第一条中的一个特例)spa
固然不彻底遵照上面的原则也可以建立immutable的类,好比String的hashcode就不是final的,但它能保证每次调用它的值都是一致的,不管你多少次计算这个值,它都是一致的,由于这些值的是经过计算final的属性得来的!线程
下面是一个例子:code
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对象会创造很大的价值。