Java mutable对象和immutable对象的区别说明

Java mutable对象和immutable对象的区别

今天读jdk源码中Map.java时看到一句话:

great care must be exercised if mutable objects are used as map keys;

第一次知道mutable对象这个概念,google了一下,维基百科定义如下:

“In object-oriented and functional programming, an immutable object (unchangeable[1] object) is an object whose state cannot be modified after it is created.[2] This is in contrast to a mutable object (changeable object) , which can be modified after it is created. In some cases, an object is considered immutable even if some internally used attributes change but the object's state appears to be unchanging from an external point of view. For example, an object that uses memoization to cache the results of expensive computations could still be considered an immutable object.”

在面向对象和函数式编程中,一个immutable对象(不可变对象)是指一旦创建之后状态不可改变的对象。

mutable对象(可变对象)是指创建之后也可以修改的对象。

在有些情况下,对象也被认为是不可变的(immutable),即,一个对象包含的内部使用的属性改变了,但从外部看对象的状态并没有改变。

例如,一个使用memoization来缓存复杂计算结果的对象仍然被看作是不可变(immutable)对象.

在面向对象编程中,String 以及其他的具体对象都被看作是不可变(immutable)对象,以提高可读性和运行效率。

不可变对象有几个优点:

线程安全

易于理解

比可变对象有更高的安全性

Java中不可变对象的经典例子就是String类的实例:

String s = "ABC";
s.toLowerCase();

toLowerCase()方法不会改变s中包含的数据“ABC”。而是创建一个新的String对象并将其初始化为“abc”,然后返回这个新对象的引用。

尽管String类声明中没有提供让它成为不可变对象的语法,但是,String类的方法中没有方法去改变一个String包含的数据,这就使得它是不可变的。

Java中关键字final用于声明原始数据类型(primitive types)和对象引用为不可变对象,但是它不能使对象本身变为不可变对象。

原始数据类型(primitive types)变量(int, long, short等)定义之后还可以再重新赋值,可以使用final阻止这样的赋值。

int i = 42; //int is of primitive type
i = 43; // OK

final int j = 42;
j = 43; // does not compile. j is final so can't be reassigned

仅仅使用final关键字还不能让引用类型(reference types)成为不可变对象,final只能阻止重新赋值。

final MyObject m = new MyObject(); //m is of reference type
m.data = 100; // OK. We can change state of object m (m is mutable and final doesn't change this fact)
m = new MyObject(); // does not compile. m is final so can't be reassigned

原始类型包装类(primitive wrappers)(Integer,Long, Short, Double, Float, Character, Byte, Boolean)也都是不可变的。

Java mutable 和 immutable类型

含义解释

immutable : variables that are assigned once and never reassigned.

mutable : When you assign to a variable or a field, you're changing where the variable's arrow points. You can point it to a different value. When you assign to the contents of a mutable value – such as an array or list – you're changing references inside that value.

基本类型及其封装对象类型都是不可变的

图形化解释 Snapshot Diagram

mutable:

immutable:

举例

例如String和StringBuilder:

1. String是immutable的,每次对于String对象的修改都将产生一个新的String对象,而原来的对象保持不变。

2. StringBuilder是mutable,因为每次对于它的对象的修改都作用于该对象本身,并没有产生新的对象。

如何保证自己创建的类是immutable类

  • 所有成员都是private final。
  • 不提供对成员的改变方法,setXX
  • 确保所有的方法不会被重写。手段有两种:使用final Class(强不可变类),或者将所有类方法加上final(弱不可变类)。
  • 如果某一个类成员不是原始变量(例如int,double)或者不可变类,必须通过在成员初始化或者使用get方法时要通过深度拷贝方法,来确保类的不可变。

优缺点

使用不可变类型,对其频繁修改会产生大量的临时拷贝(需要垃圾回收) ;

可变类型最 少化拷贝以提高效率。

使用可变数据类型,可获得更好的性能 ,也适合于在多个模块之间共享数据 。例如全局变量。

不可变类型更“安全”, 在其他质量指标上表现更好。

对可变类型可能造成的风险,我们通过防御式拷贝(深度拷贝),给客户端返回一个全新的可变类型的对象,大部分时候该拷贝不会被客户端修改, 可能造成大量的内存浪费。

深度拷贝

当只是引用传递或者根据对象的值创建新的值,称为“浅复制”,当原对象的发生改变时,根据上面方式创建的新对象的也会随之改变;

而如果采用深度复制,那是真正的复制了一份新的对象,新对象的与原对象不存在任何关联,原对象发生改变不会影响新对象。

时间: 2021-06-10

java安全编码指南之:Mutability可变性详解

简介 mutable(可变)和immutable(不可变)对象是我们在java程序编写的过程中经常会使用到的. 可变类型对象就是说,对象在创建之后,其内部的数据可能会被修改.所以它的安全性没有保证. 而不可变类型对象就是说,对象一旦创建之后,其内部的数据就不能够被修改,我们可以完全相信这个对象. 虽然mutable对象安全性不够,但是因为其可以被修改,所以会有效的减少对该对象的拷贝. 而immutable对象因为不可改变,所以尝试对该对象的修改都会导致对象的拷贝,从而生成新的对象. 我们最常使用

java ImmutableMap的使用说明

ImmutableMap:一个不可变集合 java中的Immutable对象: 简单地说,如果一个对象实例不能被更改就是一个Immutable的对象,Java SDK提供的大量值对象,比如String等都是Immutable的对象. 创建ImmutableMap: Map<String,Object> immutableMap = new ImmutableMap.Builder<String,Object>().build(); 在创建时放值: Map<String,Obj

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

一.不可变类简介 不可变类:所谓的不可变类是指这个类的实例一旦创建完成后,就不能改变其成员变量值.如JDK内部自带的很多不可变类:Interger.Long和String等. 可变类:相对于不可变类,可变类创建实例后可以改变其成员变量值,开发中创建的大部分类都属于可变类. 二.不可变类的优点 说完可变类和不可变类的区别,我们需要进一步了解为什么要有不可变类?这样的特性对JAVA来说带来怎样的好处? 1.线程安全 不可变对象是线程安全的,在线程之间可以相互共享,不需要利用特殊机制来保证同步问题,因

Immutable 在 JavaScript 中的应用

Mutable 对象 在 JavaScript 中,对象是引用类型的数据,其优点在于频繁的修改对象时都是在原对象的基础上修改,并不需要重新创建,这样可以有效的利用内存,不会造成内存空间的浪费,对象的这种特性可以称之为 Mutable,中文的字面意思是「可变」. 对于 Mutable 的对象,其灵活多变的优点有时可能会成为其缺点,越是灵活多变的数据越是不好控制,对于一个复杂结构的对象来说,一不小心就在某个不经意间修改了数据,假如该对象又在多个作用域中用到,此时很难预见到数据是否改变以及何时改变的.

javascript中的变量是传值还是传址的?

这个标题念起来有点拗口,但却是理解数据结构的关键.标题中的4个术语,对应的英文分别是:shallow copy(注意,不是shadow copy).deep copy.pass by value.pass by reference(或pass by address).传址和传引用是一回事. 一门编程语言的核心是数据结构,粗略来讲,可以把数据结构分成不可变类型(immutable)和可变类型(mutable).为什么这么分呢?这涉及到内存分配问题.对于不可变类型,只要分配有限的内存空间即可,而对于

JavaScript中的值类型详细介绍

计算机程序的实质很大程度上可以说是机器对各种信息(值)的操作与读写.在JavaScript中,存在多种类型的值,这些值分成两大类:Primitive(基本类型)和Object(对象). Primitive JavaScript中Primitive有5种类型: 1.Number.所有的数字,无论是整数还是小数,均为Number类型. 2.String.字符串类型. 3.Boolean.布尔类型,true或者false. 4.null.此类型只有null一个值. 5.undefined.此类型只有u

深入理解JavaScript中的箭头函数

从一开始箭头就是 JavaScript 的一部分,在第一个 JavaScript 中就建议将内联的脚本代码包裹在 HTML 的注释中,这可以防止那些不支持 JavaScript 的浏览器错误滴将你的代码显示为明文.你也许写过下面这样的代码: <script language="javascript"> <!-- document.bgColor = "brown"; // red // --> </script> <scri

详解Immutable及 React 中实践

有人说 Immutable 可以给 React 应用带来数十倍的提升,也有人说 Immutable 的引入是近期 JavaScript 中伟大的发明,因为同期 React 太火,它的光芒被掩盖了.这些至少说明 Immutable 是很有价值的,下面我们来一探究竟. JavaScript 中的对象一般是可变的(Mutable),因为使用了引用赋值,新的对象简单的引用了原始对象,改变新的对象将影响到原始对象.如 foo={a: 1}; bar=foo; bar.a=2 你会发现此时 foo.a 也被

JavaScript中立即执行函数实例详解

前言 js立即执行函数可以让你的函数在创建后立即执行,js立即执行函数模式是一种语法,可以让你的函数在定义后立即被执行,这种模式本质上就是函数表达式(命名的或者匿名的),在创建后立即执行. ( function(){-} )()和( function (){-} () )是两种javascript立即执行函数的常见写法,最初我以为是一个括号包裹匿名函数,再在后面加个括号调用函数,最后达到函数定义后立即执行的目的,后来发现加括号的原因并非如此. 下面话不多说了,来一起看看详细的介绍吧. 通常我们声

JavaScript中正则表达式的概念与应用

今天和大家分享一些关于正则表达式的知识和在javascript中的应用.正则表达式简单却又不简单,比如以前我的老师给我们讲的时候就说这个东西入门的话二三十分钟就精通了,一旦没有入门那就可几天都补不回来.于是当初就很认真的学习并研究了它.没想到正则表达式不仅代码简洁,而且在实际的操作中为前端工程师们省事了不少.总所周知,用户在浏览页面的时候,唯一和数据打交道的就是表单了,关于表单的验证,其实有很多中方法,接下来,我就会给大家分享两种,一种是普通繁琐的方法,一种是正则表达式,看看它到底能够给表单带来

Javascript中正则表达式的使用及基本语法

前面的话 正则表达式在人们的印象中可能是一堆无法理解的字符,但就是这些符号却实现了字符串的高效操作.通常的情况是,问题本身并不复杂,但没有正则表达式就成了大问题.javascript中的正则表达式作为相当重要的知识,本文将介绍正则表达式的基础语法 定义 正则表达式(Regular Expression)是一门简单语言的语法规范,是强大.便捷.高效的文本处理工具,它应用在一些方法中,对字符串中的信息实现查找.替换和提取操作 javascript中的正则表达式用RegExp对象表示,有两种写法:一种

JavaScript中的面向对象介绍

对象 创建 对象 构造函数 公有.私有.特权.静态成员 this.call和apply 异常处理 继承 原型 对象 在JavaScript,可以说everything is object,那么什么是对象?对象就是包含一组变量和函数的集合.在其它面向对象语言中对象是由类的实例化而来,JavaScript是基于原型的面向对象语言,没有类的概念,对象派生自现有对象的副本.JavaScript中对象可以分为两类:Function和Object. 创建对象 为了提高效率,JavaScript自带内置对象,

Javascript中的对象和原型(二)

在上篇文章中JavaScript中的对象和原型(一)提到了JavaScript中对象的创建的一些基本操作,接下来讨论下继续讨论. 一 工厂模式 我们知道,要创建一个对象我们可以用如下代码: var user = new Object(); //使用new运算符创建一个对象 user.name = '念在三角湖畔'; //给对象添加属性 user.age = 22; user.address = '湖北武汉'; alert(user.name + " " +user.age);//返回