论immutable不可变性

什么叫immutable和mutable?简单来讲,一个immutable的对象一旦被创建好,它的状态将不会改变。反过来,如果一个类的实例是immutable的,那么我们把这个类也称作immutable class。

immutable的优势

  • 便于多线程编程
  • 方便地作为hashtable的key
  • 便于比较状态

说明:本身变化才叫变化,类似string,int(等基元值类型)默认已经是不可变的,如果你修改他们,只是重新分配一个新的而矣。如果是自定义的值类型struct,最好也指定为immutable。

通过readonly来指定。

C#中immutable的实现

经典的immutable class

class Contact
{
    public Contact(String fullName, String phoneNumber)
    {
        this.fullName= fullName;
        this.phoneNumber= phoneNumber;
    }

    public Contact ChangeNumber(String newNumber)
    {
        //创建一个新实例
        return new Contact (this.fullName, newNumber);
    }

    readonly String fullName;
    public String FullName { get { return fullName; }}

    readonly String phoneNumber;
    public uint PhoneNumber{ get { return phoneNumber; }}
}

这个例子几乎无须再解释,每次changeNumber的时候就构造一个新的Contact对象。

C# 对immutability的支持离不开这两个关键字: constreadonly。C#的编译器使用这两个关键字来确保某创建好的对象的状态不会发生改变。之所以提供这两个关键字,自然是因为它们还是有所区别的。readonly允许在构造器中改变它的状态(初始化),而const则不行。例如:

class cnblogs{
   Article(string author,string title) { 

      a_title= title; 
      authorName = author; // 编译此处会报错
   }

   readonly string a_title;
   const string authorName = "Freesc";
}

(其他关于readonly和const的讨论,见这里

现在也许你会问,如果我的对象通过一个readonly的字段引用了另一个对象会怎样呢?引用的对象的状态会发生改变么?答案是肯定的,看下面的例子:

public class C 

    private static readonly int[] ints = new int[] { 1, 2, 3 };
    public static int[] Ints { get { return ints; }

 }

这里如果我们尝试在C中改变数组的值:C.ints = null;是无效的操作,这就是一种所谓的“引用不可变”,注意这里只是说引用不可变,如果你尝试在C外部使用:C.Ints[1] = 123;这样的操作,你会发现数组本身其实是可以改变的。我们姑且可以把ints字段称之为“浅”不可变字段。所以你可以相对灵活的指定你需要immutable的字段,可以参考Eric Lippert的文章.

与hashtable的相关性,只有immutable的对象作为hash的键,才能保证hash值始终为常量。当然,通常hash的值是从对象的某些状态(或者子状态)计算而来,而对象的这些状态(子状态)应为immutable。

以下摘取,可以释疑

In Java strings are immutable. If we have a string and make changes to it, we get new string referenced by the same variable:

String str = "abc";
str += "def"; // now str refers to another piece in the heap containing "abcdef"
              // while "abc" is still somewhere in the heap until taken by GC

It‘s been said that int and double are immutable in C#. Does it mean that when we have int and later change it, we would get new int "pointed" by the same variable? Same thing but with stack.

int i = 1;
i += 1; // same thing: in the stack there is value 2 to which variable
        // i is attached, and somewhere in the stack there is value 1

Is that correct? If not, in what way is int immutable?

You haven‘t changed (and cannot change) something about the int; you have assigned a new int value (and discarded the old value). Thus it is immutable.

Consider a more complex struct:

var x = new FooStruct(123);
x.Value = 456; // mutate
x.SomeMethodThatChangedInternalState(); // mutate

x = new FooStruct(456); // **not** a mutate; this is a *reassignment*

However, there is no "pointing" here. The struct is directly on the stack (in this case): no references involved.

时间: 2024-11-08 22:52:35

论immutable不可变性的相关文章

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

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

JAVA不可变类(immutable)机制与String的不可变性

不可变类:是指这个类实例一旦创建,就不能不该其成员变量的值 优点: 1.线程安全 对象的值无法改变,降低并发错误的可能性 2.效率高 当一个对象需要复制时,就只需要复制对象地址,不用复制本生 不变性,保证了hashcode的唯一性,每次缓存时不必重新计算hashcode,所以常用string作为key 3.便于测试 而且如果程序里的变量都是immutable 的话 side effect就比较小 程序只要写好测一遍基本没有什么bug 缺点: 每一次改变都需要产生新的对象,容易产生很多垃圾 设计方

【JDK源码分析】String的存储区与不可变性(转)

// ... literals are interned by the compiler // and thus refer to the same object String s1 = "abcd"; String s2 = "abcd"; s1 == s2; // --> true // ... These two have the same value // but they are not the same object String s1 = new

Java多线程-线程安全与不可变性

以下内容转自http://ifeve.com/thread-safety-and-immutability/: 当多个线程同时访问同一个资源,并且其中的一个或者多个线程对这个资源进行了写操作,才会产生竞态条件.多个线程同时读同一个资源不会产生竞态条件. 我们可以通过创建不可变的共享对象来保证对象在线程间共享时不会被修改,从而实现线程安全.如下示例: public class ImmutableValue{ private int value = 0; public ImmutableValue(

1.4.2 理解使用不可变性的代码

在前面介绍函数式风格的好处时,我们讨论过不可变性(immutability).我们使用的示例是一个带边框的椭圆,但是代码的具体行为并不清楚.当我们用不可变对象重写了代码以后,它就变得更容易理解.在后面的章节中,我们会回到这个主题并更详细地讨论.此示例的目的是显示在实践中不可变的对象的表现. 再次强调,如果你在此时没能全部掌握,也不要担心.想象一下,我们正在编写一个游戏,其中的角色就是我们的目标,角色可以用类来表示,下面的清单是这个类的一部分: Listing 1.7 Immutable repr

多线程学习之二坚不可摧模式Immutable pattern

Immutable pattern[坚不可摧模式] 一:immutable pattern的参与者--->immutable(不变的)参与者        1.1:immutable参与者是一个字段的值都无法更改的类.        1.2:immutable也没有任何用来更改字段值的方法.        1.3:immutable参与者方法不需要设置synchronized 二:immutable pattern模式什么时候使用--->当实例产生后,状态不再变化时        2.1实例状

多线程程序设计学习(3)immutable pattern模式

Immutable pattern[坚不可摧模式] 一:immutable pattern的参与者--->immutable(不变的)参与者        1.1:immutable参与者是一个字段的值都无法更改的类.        1.2:immutable也没有任何用来更改字段值的方法.        1.3:immutable参与者方法不需要设置synchronized 二:immutable pattern模式什么时候使用--->当实例产生后,状态不再变化时        2.1实例状

Java基础:String不可变性和final修饰

转载请注明出处: jiq?钦's technical Blog - 季义钦 String的不可变性 Java规定String是不可变的(immutable).事实上这个不可变具备两层含义: 1 内容不可变 不论什么看起来改动它们的操作.实际上都是又一次new出一个对象. String s = new String("111"); String newS = s; newS = "dsfsd"; System.out.println(s); //111 假设不能做到内

Java中String类型的不可变性和驻留池

一 基本概念 可变类和不可变类(Mutable and Immutable Objects)的初步定义: 可变类:当获得这个类的一个实例引用时,可以改变这个实例的内容. 不可变类:不可变类的实例一但创建,其内在成员变量的值就不能被修改.其中String类就是不可变类的经典应用. 二 例子 package cn.xy.test; public class StringTest{ /**  * a的值在编译时就被确定下来,故其值"xy"被放入String的驻留池(驻留池在堆中)并被a指向.