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方法时要通过深度拷贝方法,来确保类的不可变。

优缺点

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

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

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

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

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

深度拷贝

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

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

(0)

相关推荐

  • Immutable 在 JavaScript 中的应用

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

  • 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安全编码指南之:Mutability可变性详解

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

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

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

  • 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] o

  • 详解Java中的不可变对象

    不可变对象想必大部分朋友都不陌生,大家在平时写代码的过程中100%会使用到不可变对象,比如最常见的String对象.包装器对象等,那么到底为何Java语言要这么设计,真正意图和考虑点是什么?可能一些朋友没有细想过这些问题,今天我们就来聊聊跟不可变对象有关的话题. 一.什么是不可变对象 下面是<Effective Java>这本书对于不可变对象的定义: 不可变对象(Immutable Object):对象一旦被创建后,对象所有的状态及属性在其生命周期内不会发生任何变化. 从不可变对象的定义来看,

  • Java反射(Class类,Class对象获取)

    目录 Java反射超详解 1.反射基础 1.1Class类 1.2类加载 2.反射的使用 2.1Class对象的获取 2.2Constructor类及其用法 2.3Field类及其用法 Java反射超详解 1.反射基础 Java反射机制是在程序的运行过程中,对于任何一个类,都能够知道它的所有属性和方法:对于任意一个对象,都能够知道它的任意属性和方法,这种动态获取信息以及动态调用对象方法的功能称为Java语言的反射机制. Java反射机制主要提供以下这几个功能: 在运行时判断任意一个对象所属的类

  • 带你用Java全面剖析类和对象

    目录 一.面向过程?面向对象? 二.类和类的实例化 2.1普通成员变量和普通成员方法 2.2 静态成员变量和静态成员方法 三.封装 3.1 private 3.2 getter 和 setter 四.构造方法 4.1 基本语法 4.2 this 关键字 五.代码块 5.1 普通代码块 5.2 构造代码块 5.3 静态代码块 5.4 注意事项 六.快捷方法 6.1 toString方法 6.2 setter / getter 方法 6.3 构造方法(快捷) 总结 一.面向过程?面向对象? C 语言

  • Java 精炼解读类和对象原理

    面向对象.面向过程 什么是类? 什么是对象? 这是非常抽象的两个概念!!!!!!!! 在说清楚类和对象的概念之前,给大家讲一下什么是面向对象.面向过程,以此来推出我们类和对象的概念. 面向过程:以洗衣服为例:拿盆.放水.放衣服.放洗衣粉.手搓.换水.拧干.晾衣服,这个过程就是面向过程.  面向对象:以洗衣服为例:人把衣服放进洗衣机,倒入洗衣粉,洗完晾干,不需要关心洗衣服整个过程是怎么完成的,只需要找对象,创建对象,使用对象.在好比我们使用toString函数,我们并不关心toString函数具体

  • java对象与json对象之间互相转换实现方法示例

    本文实例讲述了java对象与json对象之间互相转换实现方法.分享给大家供大家参考,具体如下: import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import net.sf.json.JSONArray; import net.sf.json.JSONObject; public class MainClass { public st

  • js+ajax处理java后台返回的json对象循环创建到表格的方法

    本文实例讲述了js+ajax处理java后台返回的json对象循环创建到表格的方法.分享给大家供大家参考,具体如下: //注:LO是表格的id: 需要自己创建表头, n行,9列的表格: var tab_id; function varify(cardinno) { tab_id=document.getElementById("Layer1"); displayDiv(); tab_id.style.display="none"; var url="get

  • Java Socket实现的传输对象功能示例

    本文实例讲述了Java Socket实现的传输对象功能.分享给大家供大家参考,具体如下: 前面两篇文章介绍了怎样建立Java Socket通信,这里说一下怎样使用Java Socket来传输对象. 首先需要一个普通的对象类,由于需要序列化这个对象以便在网络上传输,所以实现java.io.Serializable接口就是必不可少的了,如下: package com.googlecode.garbagecan.test.socket.sample3; public class User implem

  • Java反射之类的实例对象的三种表示方式总结

    如下所示: <span style="font-size:14px;">package com.imooc.reflect; public class ClassDemo1 { public static void main(String[] args) { //Foo的实例对象如何表示 Foo foo1 = new Foo();//foo1就表示出来了 //Foo这个类,也是一个实例对象,Class类的实例对象,如何表示呢. //任何一个类都是Class的实例对象,这个实

  • java对象与json对象间的相互转换的方法

    工程中所需的jar包,因为在网上不太好找,所以我将它放到我的网盘里了,如有需要随便下载. 点击下载 1.简单的解析json字符串 首先将json字符串转换为json对象,然后再解析json对象,过程如下. JSONObject jsonObject = JSONObject.fromObject(jsonStr); 根据json中的键得到它的值 String name = jsonObject.getString("name"); int num = jsonObject.getInt

随机推荐