【软件构造】Mutable类型与Immutable类型


1.前言

在软件构造这门课中,对mutable类型和immutable类型的深入理解,有助于后续ADT、可维护性、可复用性的学习,因此我们有必要对其进行详细的分析说明。

我们首先明确的是,mutable类型和immutable类型均属于ADT的范围,二者关系如下图:


2.概念

immutable类:类的实例创建后成员变量值不变,若修改后,引用会指向一个实例对象。

mutable类:类的实例创建后可以通过类的方法就地修改值。


3.常见immutable类与mutable类

常见immutable类:String类;基本数据类型与其封装数据类型,如int、char、Interger、Boolean;Scanner类;经过 Collections.unmodifiableList/Map/Set() 方法处理后的集合。

常见mutable类:StringBuilder、StringBuffer、Map类、Collection类。


4.代码实践

考虑如下代码:

String str=new String("123");
str.concat("4");
System.out.println(str);

输出结果为:

为什么结果不是“1234”呢?

我们知道,java数据类型分为基本数据类型和对象数据类型(引用类型),后者类型的对象会按引用传递,这个引用,本质上是一个指针,指向存储在堆里的对象实体。所以,对于这样的变量,有着直接修改被指向的数据值让引用重新指向一个新对象两种方式。

而对于immutable类型,一旦该类初始化为一个新对象,其指向的堆中的值不可以修改,除非让其指向新的堆位置。所以,上述contact()会使用str引用指向的值重新创建一个新的对象,而不是修改str指向的对象的值。

其相应代码快照图为:

再考虑如下代码:

StringBuffer strbuf1= new StringBuffer("123");
StringBuffer strbuf2=strbuf1;
strbuf1.append("4");
System.out.println(strbuf1);
System.out.println(strbuf2);

输出为:

这里Stringbuffer为mutable类型,调用其成员方法append时,可以在引用所指向的堆中直接修改值,故输出均为“1234”。

其代码快照图为:

对于mutable类型的对象,若有多个引用,其中某一个引用对对象的值修改时,由于所有引用指向同一个对象,所以在其他引用的值被“偷偷地改变了”,而这种改变,往往是被忽略的,因此会有潜在的危险性。

比如如下代码:

strbuf2.append("5");
System.out.println(strbuf1);

在输出strbuf2时,输出结果也是“12345”。

此外在函数调用时,对于mutable类也会出现非法篡改的情况:

 1     public static StringBuilder addstr(StringBuilder p){
2 p.append("d");
3 return p;
4 }
5 public static void main(String[] args) {
6 StringBuilder str=new StringBuilder("abc");
7 System.out.println(str);
8 addstr(str);
9 System.out.println(str);
10 }

其输出为:


5.针对immutable类非法篡改的解决方案

方案一:defensive copy

在传参之前,或者在函数体内修改传入参数之前,拷贝一个新的对象

 1     public static StringBuilder addstr(StringBuilder p){
2 StringBuilder copy=new StringBuilder(p);
3 copy.append("d");
4 return copy;
5 }
6 public static void main(String[] args) {
7 StringBuilder str=new StringBuilder("abc");
8 System.out.println(str);
9 StringBuilder str1=addstr(str);
10 System.out.println(str);
11 System.out.println(str1);
12 }

输出为:

abc
abc
abcd

方案二:使用相应的immutable类替换mutable类的引用

 1     public static String addstr(String p){
2 return p+"de";
3 }
4 public static void main(String[] args) {
5 String str=new String("abc");
6 System.out.println(str);
7 String str1=addstr(str);
8 System.out.println(str);
9 System.out.println(str1);
10 }

输出为:

abc
abc
abcde

6.总结

immutable类更加安全,在软件构造过程中同时使用immutable类型的类,保证变量的值始终不变,可以重复使用,但对其修改需要进行大量拷贝,浪费时间与存储空间;

mutable类的修改不会造成空间的浪费,适合作为共享数据使用,但对其修改一定要谨慎进行。


完结~感谢阅读~️️️

【软件构造】Mutable类型与Immutable类型的更多相关文章

  1. apache软件no_ssl和openssl两种类型的区别

    apache软件同一版本有两种类型:no_ssl和openssl: openssl多了个ssl安全认证模式,它的协议是HTTPS而不是HTTP,这就是带有SSL的服务器与一般网页服务器的区别了. 一般 ...

  2. 函数索引引用的函数必须是immutable类型

    用户在使用中,可能会用到基于函数的索引,但是函数是非 immutable 类型的,导致函数索引无法创建.如: test=# create index ind_t1 on t1(to_char(crea ...

  3. 麻省理工18年春软件构造课程阅读02“Java基础”

    本文内容来自MIT_6.031_sp18: Software Construction课程的Readings部分,采用CC BY-SA 4.0协议. 由于我们学校(哈工大)大二软件构造课程的大部分素材 ...

  4. typescript枚举,类型推论,类型兼容性,高级类型,Symbols(学习笔记非干货)

    枚举部分 Enumeration part 使用枚举我们可以定义一些有名字的数字常量. 枚举通过 enum关键字来定义. Using enumerations, we can define some ...

  5. HIT2019春软件构造->Git&Github学习笔记

    由于软件构造课程需要,学习使用git,以下作为学习笔记. 一.Git初始化及仓库创建和操作  1.基本信息设置(设置签名)  命令        项目级别/仓库级别:仅在当前本地库范围内有效 git ...

  6. python的mutable变量与immutable变量

    python的变量分为mutable(可变的)和immutable类型. mutable:dict, list immutable:int , string , float ,tuple..

  7. 面向对象软件构造 (Bertrand Meyer 著)

    Part A: The Issues 议题 第一章 软件品质 第二章 面向对象的标准 Part B: The Road To Object Orientation 通向面向对象之路 第三章 模块性 第 ...

  8. 由软件构造引申的OOP与POP的心得体会

    在大一初学C语言的时候,所解决的问题都是一些轻量级的简单问题,当时写过一个教学管理系统.这个教学管理系统的功能很简单,思想就是“流水线”:按部就班的实现所有流程.要完成整个教学管理系统,实际上就是完成 ...

  9. 哈工大软件构造Lab1(2022)

    目录 一.实验目标概述 二.实验环境配置 1.安装编写java程序的IDE--IntelliJ IDEA 2.安装Git 3.安装Junit 4.GitHub Lab1仓库的URL地址 三.实验过程 ...

随机推荐

  1. spring中bean的五种作用域?Spring中的bean是线程安全的吗?

    spring中bean的五种作用域 当通过spring容器创建一个Bean实例时,不仅可以完成Bean实例的实例化,还可以为Bean指定特定的作用域.Spring支持如下5种作用域: singleto ...

  2. 列举 spring 支持的事务管理类型?

    Spring 支持两种类型的事务管理: 1. 程序化事务管理:在此过程中,在编程的帮助下管理事务.它为您提供极大 的灵活性,但维护起来非常困难. 2. 声明式事务管理:在此,事务管理与业务代码分离.仅 ...

  3. 学习openldap03

    ldap统一认证架构 一.ldap目录服务介绍什么是目录服务?  目录是一类为了浏览和搜索数据而设计的特殊的数据库.例如,为人所熟知的微软公司的活动目录(active directory)就是目录数据 ...

  4. servlet中的HttpServletRequest对象

    HttpServletRequest对象表示客户端浏览器发起的请求,当客户端浏览器通过HTTP协议访问服务器时,Tomcat会将HTTP请求中的所有信息解析并封装在HttpServletRequest ...

  5. Linux 0.11源码阅读笔记-总览

    Linux 0.11源码阅读笔记-总览 阅读源码的目的 加深对Linux操作系统的了解,了解Linux操作系统基本架构,熟悉进程管理.内存管理等主要模块知识. 通过阅读教复杂的代码,锻炼自己复杂项目代 ...

  6. .NET程序设计实验四

    实验四  文件操作 一.实验目的 1. 掌握窗口控件的使用方法: 2. 掌握文件系统的操作方法.File 类和 Directory类的使用. 二.实验要求 根据要求,编写 C#程序,并将程序代码和运行 ...

  7. 用 JS(JavaScript )实现增删改查

    JS小例题 学习内容: 需求 总结: 学习内容: 需求 用 JavaScript 实现简单增删改查 实现代码 <!DOCTYPE html PUBLIC "-//W3C//DTD HT ...

  8. github账号&文章选题

    ----------------------------------------------------------- https://github.com/yanpanjiao     github ...

  9. python修改Gsettings的配置文件

    GSettings 的配置文件是 xml 格式的,文件需以 .gschema.xml 结尾,文件名通常与 id 相同.配置文件安装在 /usr/share/glib-2.0/schemas/ 目录下, ...

  10. Python中用类实现对象和封装

    """ 用类实现对象和封装 对象:对应客观世界的事物,将描述事物的一组数据和与这组数据有关的操作封装在一起, 形成一个实体,这个实体就是对象 类:具有相同或相似性质的对象 ...