不可变类(转)

如何在Java中写出Immutable的类?

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

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

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

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

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

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

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

下面是一个例子:

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-12-20 02:12:44

不可变类(转)的相关文章

不可变类

所谓不可变类,是指当创建了这个类的实例后,就不允许修改它的属性值. 在C#中,String类就是一个不可变类.这也就是为什么当我们创建一个String对象后为其再次赋值后创建的是另一个实例的原因. 下面例举一个例子. static void Main(string[] args) { string str1 = "I'm a student"; string str2 = str1; str2 = "I'm a teacher"; Console.WriteLine

Java中的不可变类

本文与个人博客 zhiheng.me 同步发布,标题: Java中的不可变类. 不可变类(Immutable Objects):当类的实例一经创建,其内容便不可改变,即无法修改其成员变量. 可变类(Mutable Objects):类的实例创建后,可以修改其内容. Java 中八个基本类型的包装类和 String 类都属于不可变类,而其他的大多数类都属于可变类. 与引用不可变的区别 需要特别注意的是,不可变类的不可变是指该类的实例不可变而非指向该实例的引用的不可变. String s = "ab

Java 不可变类

什么是不可变类 当你获得这个类的引用时,不能改变这个类的内容: 不可变类的实例一旦创建,其成员变量就不能够被修改: 如何创建不可变类 成员变量均为private权限 不提供改变成员变量的对外接口,即set方法 所有方法均不可被重载,有两种实现方式:1) 所有方法均加上final关键字(弱不可变类) 2)使用 final class(强不可变类) 如果类的成员变量为可变子类,那么在初始化过程中,需要对这个可变子类,进行深度拷贝: 范例: 1 public class ImmuteDemo { 2

深刻理解Java中final的作用(一):从final的作用剖析String被设计成不可变类的深层原因

声明:本博客为原创博客,未经同意,不得转载!小伙伴们假设是在别的地方看到的话,建议还是来csdn上看吧(原文链接为http://blog.csdn.net/bettarwang/article/details/26744661),看代码和提问.讨论都更方便. Java中final的作用主要表如今三方面:修饰变量.修饰方法和修饰类.以下就从这两个方面来解说final的作用.在文末从final及类的设计安全性出发,论述了Java中String为何要被设计成不可变类. 1.final修饰变量 fina

无锁编程:采用不可变类减少锁的使用

很多的同学很少使用.或者干脆不了解不可变类(Immutable Class).直观上很容易认为Immutable类效率不高,或者难以理解他的使用场景.其实不可变类是非常有用的,可以提高并行编程的效率和优化设计.让我们跳过一些宽泛的介绍,从一个常见的并行编程场景说起: 假设系统需要实时地处理大量的订单,这些订单的处理依赖于用户的配置,例如用户的会员级别.支付方式等.程序需要通过这些配置的参数来计算订单的价格.而用户配置同时被另外一些线程更新.显然,我们在订单计算的过程中保持配置的一致性. 上面的例

Integer是不可变类,进入一个方法后,在里面的值的改变不会影响方法外的引用

先看一个小程序 主函数的输出并没有像想像中一样会输出3,而是输出初始化的数值0 这是因为与String类似,所有的包装类都是final类,即不可变类.虽然在代码A处看起来是改变了counter的值,但实际上是创建了另一个对象,并将方法内的counter参数的引用指向了这个新创建的对象,由于是不同的引用,所以不会对方法外的引用有任何的影响.内存图如下所示: 在刚进入方法的时候: 执行counter = counter +1之后,由于Integer是不可变类,要改变它的值,其实是创建了一个新的对象,

《Java中的不可变类》

1 //不可变类举例: 2 /* 3 下面程序试图定义一个不可变类Person类,但=因为Person类包含一个引用类型的成员变量, 4 且这个引用类是可变类,所以导致Person类也变成了可变类. 5 */ 6 class Name1 7 { 8 private String firstName; 9 private String lastName; 10 public Name1(){} 11 public Name1(String firstName,String lastName) 12

JAVA中具有实例缓存的不可变类

不可变类的实例的状态不会变化,这样的实例可以安全的被其他与之关联的对象共享,还可以安全的被多个线程共享. 为了节省内存空间, 优化程序的性能, 应该尽可能的重用不可变类的实例,避免重复创建具有相同属性值的不可变类的实例. 在 JDK1.5 的基本类库中, 对一些不可变类, 如 Integer 类作了优化, 它具有一个实例缓存,用来存放程序中经常使用的 Integer 实例.JDK1.5 的 Integer 类新增了一个参数为 int 类型的静态工厂方法 valueOf(int i),它的处理流程

可变类与不可变类的区别

可变类与不可变类的区别 所谓不可变类: 是指当创建了这个类的实例后,就不允许修改它的属性值.在JDK的基本类库中,所有基本类型的包装类,如Integer和Long类,都是不可变类,java.lang.String也是不可变类. 不可变类: 当你获得这个类的一个实例引用时,你不可以改变这个实例的内容.不可变类的实例一但创建,其内在成员变量的值就不能被修改. 如何创建一个不可变类? 这道题90%以上的人都会被挂或者只回答一半对,来看: 1. 所有成员都是private 2. 不提供对成员的改变方法,

【Java基础】JAVA不可变类(immutable)机制与String的不可变性

一.不可变类简介 不可变类:所谓的不可变类是指这个类的实例一旦创建完成后,就不能改变其成员变量值.如JDK内部自带的很多不可变类:Interger.Long和String等. 可变类:相对于不可变类,可变类创建实例后可以改变其成员变量值,开发中创建的大部分类都属于可变类. 下面的理解可能会易懂一些: {概念:不可变类的意思是创建该类的实例后,该实例的属性是不可改变的.Java中的8个包装类和String类都是不可变类.所以不可变类并不是指该类是被final修饰的,而是指该类的属性是被final修