美文网首页程序猿
[译] 不可变类有什么优势,应该如何创建?

[译] 不可变类有什么优势,应该如何创建?

作者: raymondcode | 来源:发表于2016-05-02 18:41 被阅读0次

不可变类是指对象状态在创建时就确定,之后无法改变的类。其中状态是指类的成员变量,包括原生类型和引用类型。

不可变类的优势

  • 方便构造、测试和使用
  • 线程安全,没有同步问题
  • 不需要拷贝构造方法
  • 不需要实现Clone方法
  • 可以缓存类的返回值,允许hashCode使用惰性初始化方式
  • 不需要防御式复制
  • 适合用作Map的key和Set的元素(因为集合里这些对象的状态不能改变)
  • 类一旦构造完成就是不变式,不需要再次检查
  • 总是“failure atomicity”(原子性失败):如果一个不可变对象抛出异常,它从不会保留一个烦人的或者不确定的状态

如何创建不可变类

关于创建不可变对象,Oracle也有说明:详细介绍
主要是以下几点:

  1. Don't provide "setter" methods — methods that modify fields or objects referred to by fields
  2. Make all fields final and private
  3. Don't allow subclasses to override methods. The simplest way to do this is to declare the class as final. A more sophisticated approach is to make the constructor private and construct instances in factory methods.
  4. If the instance fields include references to mutable objects, don't allow those objects to be changed:
  • Don't provide methods that modify the mutable objects.
  • Don't share references to the mutable objects. Never store references to external, mutable objects passed to the constructor; if necessary, create copies, and store references to the copies. Similarly, create copies of your internal mutable objects when necessary to avoid returning the originals in your methods.
  1. 不提供setter方法,避免对象的域被修改
  2. 将所有的域都设置为private final
  3. 不允许子类覆盖父类方法。最简单的方法是将class设为final。更好点的方式是将构造方法设为private,同时通过工厂方法来创建实例
  4. 如果域包含其他可变类的对象,也要禁止这些对象被修改:
  • 不提供修改可变对象的方法
  • 不要共享指向可变对象的引用。不要存储那些传进构造方法的外部可变对象的引用;如果需要,创建拷贝,保存指向拷贝的引用。类似的,在创建方法返回值时,避免返回原始的内部可变对象,而是返回可变对象的拷贝。

根据以上规则可以实现一个不可变类

import java.util.Date;
 
/**
* 注意实例的变量本身可能是不可变的,也可能是可变的
* 对于所有可变的成员变量,返回时需要复制一份新的
* 不可变的成员变量不用做特殊处理
* */
public final class ImmutableClass
{
 
    /**
    * Integer类是不可变的,因为它没有提供任何setter方法来改变值
    * */
    private final Integer immutableField1;
    /**
    * String类是不可变的,它也没有提供任何setter方法来改变值
    * */
    private final String immutableField2;
    /**
    * Date类是可变的,它提供了改变日期或时间的setter方法
    * */
    private final Date mutableField;
 
    // 将构造方法声明为private,确保不会有意外情况构造这个类
    private ImmutableClass(Integer fld1, String fld2, Date date)
    {
        this.immutableField1 = fld1;
        this.immutableField2 = fld2;
        this.mutableField = new Date(date.getTime());
    }
 
    // 工厂方法将创建对象的逻辑封装在一个地方
    public static ImmutableClass createNewInstance(Integer fld1, String fld2, Date date)
    {
        return new ImmutableClass(fld1, fld2, date);
    }
 
    // 不提供setter方法
 
    /**
    * Integer类是不可变的,可以直接返回成员变量的实例
    * */
    public Integer getImmutableField1() {
        return immutableField1;
    }
 
    /**
    * String类是不可变的,可以直接返回成员变量的实例
    * */
    public String getImmutableField2() {
        return immutableField2;
    }
 
    /**
    * Date类是可变的,需要注意一下
    * 不要返回原始成员变量的引用
    * 创建一个新的Date对象,内容和成员变量一样
    * */
    public Date getMutableField() {
        return new Date(mutableField.getTime());
    }
 
    @Override
    public String toString() {
        return immutableField1 +" - "+ immutableField2 +" - "+ mutableField;
    }
}

测试类

class TestMain
{
    public static void main(String[] args)
    {
        ImmutableClass im = ImmutableClass.createNewInstance(100,"test", new Date());
        System.out.println(im);
        tryModification(im.getImmutableField1(),im.getImmutableField2(),im.getMutableField());
        System.out.println(im);
    }
 
    private static void tryModification(Integer immutableField1, String immutableField2, Date mutableField)
    {
        immutableField1 = 10000;
        immutableField2 = "test changed";
        mutableField.setDate(10);
    }
}
 
Output: (content is unchanged)
 
100 - test - Tue Oct 30 21:34:08 IST 2012
100 - test - Tue Oct 30 21:34:08 IST 2012

从输出结果可以看出,用实例内部成员的引用来改变实例的值是无效的,这个类是不可变类。

原文链接

相关文章

  • [译] 不可变类有什么优势,应该如何创建?

    不可变类是指对象状态在创建时就确定,之后无法改变的类。其中状态是指类的成员变量,包括原生类型和引用类型。 不可变类...

  • Java不可变类

    1. 什么是不可变类? 2. 如何创建不可变类? 2.1通过 Collections.unmodifiable**...

  • Java不可变类

    0. 几个问题 什么是不可变类? 不可变类的优缺点是什么? 常见的不可变类有哪些?String为什么要设计成不可变...

  • String为何称为不可变类

    什么是不可变类 不可变类:所谓的不可变类是指这个类的实例一旦创建完成后,就不能改变其成员变量值。如JDK内部自带的...

  • Object-C 学习笔记

    类的申明放在 .h 文件中,类的实现放在 .m 文件中 类分为可变类、不可变类2.1. 必须在不可变对象创建时,设...

  • iOS 面试宝典

    tip1.可变集合类 和 不可变集合类的 copy 和 mutablecopy 有什么区别? 对于可变与不可变对象...

  • Guava 集合类

    不可变集合类 为什么要使用不可变集合不可变对象有很多优点,包括: 当对象被不可信的库调用时,不可变形式是安全的;不...

  • 快速创建一个可变数组的方法

    如何快速创建一个可变数组 不可变空数组: @[] 可变空数组: @[].mutableCopy

  • Java中的不可变类

    总览 不可变类定义 不可变类Immutable Objects:当类的实例一经创建,其内容便不可改变,即无法修改其...

  • Java 不可变类(immutable)机制与 String 的

    不可变类介绍 不可变类: 所谓的不可变类是指这个类的实例一旦创建完成后,就不能修改其成员变量值。如JDK 内部自带...

网友评论

    本文标题:[译] 不可变类有什么优势,应该如何创建?

    本文链接:https://www.haomeiwen.com/subject/sjknkttx.html