Java可变类型与不可变类型

article/2025/6/24 19:32:52

 一、可变类型(mutable type)与不可变类型(immutable type)

       已知,基本数据类型都是不可变类型;引用(对象)数据类型既有可变类型,也有不可变类型

首先区分:改变一个变量、改变一个变量的值,二者有何区别?

  • 改变一个变量:将该变量指向另一个存储空间。——修改指向
  • 改变一个变量的值:将该变量当前指向的存储空间中写入一个新的值。——修改存储内容

接着区分:可变类型(mutable type)与不可变类型(immutable type)

  • 不变数据类型:一旦被创建,其值不能改变(但可以修改指向)
  • 可变数据类型:拥有方法可以修改自己的值/引用

(1)不可变类型(immutable type)

        以String为例,String是不可变类型,一旦被创建,其值不能改变

         当String类型(以至于扩展到其他不可变类型)发生改变时,它会再开辟一个新空间,创建一个新的String对象,存储改变后的值,并指向这个新的内存空间(原来的内存空间如果不再被使用,就会变成垃圾)

  • 缺点:使用不可变类型,对其频繁修改会产生大量的临时拷贝(需要垃圾回收)
  • 优点:安全,内部存储值不会被篡改

(但是当变量类型为基本数据类型(没有引用时),我讲不清内部修改值的具体过程,猜测有可能是在栈中开辟新空间存储新值,变量名对应新值而非旧值——或者变量名与变量值之间有类似这样的机制,如果有大佬知道可以告诉我orz)

(2)可变类型(mutable type)

        以StringBuilder为例,StringBuilder是可变类型,可以修改自己的值/引用

         当StringBuilder类型(以至于扩展到其他可变类型)发生改变时,直接对引用指向的内存修改数值,而非再开辟新的内存空间,创建新对象

  • 优点:可变类型因为最少化拷贝,可以提高效率
  • 缺点:如果有多个引用(别名),使用可变类型就非常不安全

(3)final的使用

To make a reference immutable, declare it with the keyword final

 对于final,它限制了变量的引用不可更改,但是并不限制引用指向的内存里的数据的修改

总结:

  • final + 基本数据类型 / 不可变的引用数据类型:如 final int——不可修改该变量

(基本数据类型没有引用,且本身为不可变类型,不具有方法来修改其值)

  •  final + 可变的引用数据类型:final List——只限制了引用不可更改,但是并不限制引用指向的内存里的数据的修改

二、问题代码范例

package aboutDate;
import java.util.Date;
public class Period {private  Date start,end;public Period(Date start,Date end){if(start.after(end))System.out.println("Error");this.start=start;this.end=end;}public Date getStart(){return this.start;}public Date getEnd(){return this.end;}public static void main(String argv[]){Date start =new Date();Date end =new Date();//实例化类,并赋初值Period p=new Period(start,end);System.out.println(p.getEnd());//修改endend.setYear(78);System.out.println(p.getEnd());//利用返回值修改p.getEnd().setYear(2000);System.out.println(p.getEnd());}
}

运行结果: 

         尽管我们在设计类时,已经将start和end设计成私有属性,但由于Date为可变类型,当存在多个引用【main里的start(end),Period里的this.start(end),getStart(getEnd)返回值】,均指向同一个内存,这个内存里的值就有可能在无意中被篡改。这其实就是一种表示泄露,客户端获取了类内成员的引用,存在误改的可能,使得软件内部存在漏洞,这并不是我们期望看到的。

三、修改思路

(1)防御式拷贝——消除多个引用指向同一内存的情况

实际修改的地方

public Period(Date start,Date end){if(start.after(end))System.out.println("Error");this.start=new Date(start.getTime());this.end=new Date(end.getTime());}public Date getStart(){return new Date(this.start.getTime());}public Date getEnd(){return new Date(this.end.getTime());}

完整代码如下: 

package aboutDate;
import java.util.Date;
public class Period {private  Date start,end;public Period(Date start,Date end){if(start.after(end))System.out.println("Error");this.start=new Date(start.getTime());this.end=new Date(end.getTime());}public Date getStart(){return new Date(this.start.getTime());}public Date getEnd(){return new Date(this.end.getTime());}public static void main(String argv[]){Date start =new Date();Date end =new Date();Period p=new Period(start,end);System.out.println(p.getEnd());end.setYear(78);System.out.println(p.getEnd());p.getEnd().setYear(2000);System.out.println(p.getEnd());}
}

运行结果(可见修改成功——客户端不能随意修改类的属性): 

        防御性拷贝,就是创建一个新的对象,而不是单纯的把引用指向同一个内存。这样实现了局部变量,不会涉及共享以及同一个内存,只有一个引用,保证了数据的安全性。

(2)修改数据结构

        使用Java内部其他的不可变类型,如LocalDateTime, Instant等等,但是需要对代码进行较大的修改(否则出现类型不匹配的问题),此处附上Date与LocalDateTime转化的博客链接

localDateTime与Date转化_小馒头味豆浆的博客-CSDN博客_localdatetime转换date

四、总结

        可变与不可变类型各有各的优缺点。可变类型更灵活,可以减少拷贝次数,在需要频繁修改变量值的场合效率更高;但是当有多个引用指向同一个变量时,就会存在安全隐患,要小心数据在无意中被篡改,这种情况下就要尽量避免使用可变类型。此外,当设计封装类时,如果使用了可变类型,要防止函数返回可变类型的引用,以及初始化时类属性和调用者里的变量指向同一内存,否则就存在表示泄露,不是一个好的ADT。

        不可变类型较为呆板,当需要频繁修改变量值时,可能会产生大量的内存垃圾;但是安全系数高,数据不会被篡改。

        选择可变与不可变类型,就是在效率与安全之间做折中,需要依据场合来判断。

        


http://chatgpt.dhexx.cn/article/b5pMl4Me.shtml

相关文章

Python中的可变对象

文章目录 可变对象与不可变对象关于对象图解可变对象 可变对象与不可变对象 关于什么是对象不是这篇的重点,可查看这篇 Python中面向对象的简单应用 可变对象就是说对象的值是可以改变的,序列中可变对象有list 不可变对象有str、tuple 那么问题又来了…

可变剪切|rmats

可变剪切 可变剪切(或选择性剪切)是一个过程,即主要基因或者mRNA前体转录所产生的RNA的外显子以多种方式通过RNA剪切进行重连。由此产生的不同的mRNA可能被翻译成不同的蛋白质构体,因此,一个基因可能编码多种蛋白质。 rmats 下面是小编使用…

python中的可变和不可变类型,每种类型的常用

方法及原理实现 可变数据类型 可变数据类型 :当该数据类型的对应变量的值发生了改变,那么它对应的内存地址不发生改变,对于这种数据类型,就称可变数据类型 不可变数据类型 不可变数据类型: 当该数据类型的对应变量的值发生了改变,…

JavaScript 中的可变和不可变

原文:Mutable and immutable in JavaScript https://blog.devgenius.io/mutable-and-immutable-in-javascript-78a3cbc6187c 根据 Mozilla 的定义- 可变(Mutable)是一种可以更改的变量。 在 JavaScript 中,只有对象和数组是可变的,原始值不…

python可变和不可变

python进阶笔记 一、python中的可变和不可变二、简单可变类型拷贝1、Python的深浅拷贝2、深浅拷贝具体代码实现 三、复杂可变类型拷贝四、简单不可变类型拷贝五、复杂不可变类型拷贝1、不可变类型的深浅拷贝-嵌套类型 六、切片拷贝,字典拷贝1、切片拷贝2、字典拷贝 …

vsftpd 配置(中)

原贴:http://www.ititgo.cn/news_view.asp?newsid575 vsftpd 配置(中) 录入员:admin 来源: 加入时间:2007-6-4 11:30:32 点击:274 <script type"text/javascript"> </script> <script src"http://pagead2.googlesyndication.com/pagead/show_…

linux vsftpd 模式,Linux下的Vsftpd配置篇

1.主动与被动模式 1)主动模式(PORT方式) 连接过程为:客户端向服务器FTP端口(默认是21)发送连接请求,服务器接受连接,建立一条命令链路。当需要传送数据时,客户端在命令链路上用PORT命令告诉服务器:我打开了XX端口,你过来连接我,于是服务器从20号端口向客户端的XX端口发送…

ftp服务器vsftpd配置文件,最全面的vsftpd配置文件详解

最详细的vsftpd配置文件&#xff0c;分享给大家。 注意&#xff1a; 使用匿名登入时&#xff0c;所登入的目录。默认值为/var/ftp。注意ftp目录不能是777的权限属性&#xff0c;即匿名用户的家目录不能有777的权限。 对于用户的访问控制可以通过/etc/vsftpd目录下的vsftpd.user…

ftp服务器vsftpd配置文件,vsftpd配置文件详解及ftp服务器搭建

本文介绍如何在linux上搭建ftp服务器&#xff0c;并且给出了vsftpd 的配置的中文详解&#xff0c;要搭建ftp的同学可以认真看看&#xff0c;其中的配置文件必备全部记忆&#xff0c;在以后配置时可以查看这篇文章。 一、vsftps服务器的配置文件中文详解 vsftps服务器的配置文件…

大数据所具备的四个特点,清楚知道大数据原理原则

说起大数据&#xff0c;估计大家都觉得只听过概念&#xff0c;但是具体是什么东西&#xff0c;怎么定义&#xff0c;没有一个标准的东西&#xff0c;因为在我们的印象中好像很多公司都叫大数据公司&#xff0c;业务形态则有几百种&#xff0c;感觉不是很好理解&#xff0c;所以…

计算机存储容量的基本单位pb,pb存储单位是什么

pb存储单位是一种计算机存储单位&#xff0c;pb的英文全称是Petabytes&#xff0c;其中文名叫拍字节&#xff1b;计算机存储单位一般用字节Byte、千字节KB、兆字节MB、吉字节GB、太字节TB、拍字节PB、艾字节EB等表示。 本文操作环境&#xff1a;Windows7系统&#xff0c;Dell G…

zb计算机术语,容量1zb等于多少kb

满意答案 nnn08nnn08 2017.05.28 采纳率&#xff1a;57% 等级&#xff1a;9 已帮助&#xff1a;115人 1KB1024B&#xff1b;1MB1024KB10241024B。其中1024210。  1B(byte&#xff0c;字节)8bit(见下文)&#xff1b;  1KB(Kibibyte&#xff0c;千字节)1024B2^10B&#xf…

计算机存储1pb等于多少kb,存储容量:1TB等于多少GB?1PB等于多少TB?1EB等于多少PB?

满意答案 youki203. 2013.09.11 采纳率&#xff1a;45% 等级&#xff1a;11 已帮助&#xff1a;12389人 存储容量:是该存储设备上可以存储数据的最大数量&#xff0c;通常使用千字节(kb kilobyte)、兆字节(MB megabyte)、吉字节(GB, gigabyte)、太字节(TB &#xff0c;terab…

word中如何快速引用参考文献

最近一直忙于论文的修改&#xff0c;在修改过程中发现参考文献引用是一个问题&#xff0c;下面结合网上的资源给出了如何快速引用参考文献。 主要分为两大步骤&#xff0c;生成编号项、插入超级链接 1、自动生成编号项 1.1、选种参考文献区域&#xff0c;如下图&#xff1a;…

Word 2016 撰写论文(2): 交叉引用

在利用Word编辑论文时&#xff0c;谁也不可能保证自己撰写的文档会一次性成功&#xff0c;不做任何修改&#xff0c;这就避免的会碰到增加或删减某些图片或表格的情况&#xff0c;以及对插入图片的顺序进行变更&#xff0c;这就产生一个问题&#xff0c;为了是文档产生图文并茂…

Word引用文献设置双向链接

1. 修改参考文献编号格式 2. 选中正文中引用的标号例如&#xff1a; 3. 保持选中的状态下&#xff0c;点击引用&#xff1a; 4. 再点击交叉引用&#xff1a; 5. 引用内容选择“段落编号(完整上下文)”&#xff0c;然后选择具体的引用文献&#xff1a; 6. 如果要在两条文献之中…

如何更新word文档中的文献引用编号?

最近用word写毕业论文&#xff0c;遇到一个小问题&#xff0c;就是使用 “交叉引用” 引用参考文献的时候&#xff0c;文档中插入的编号不能随参考文献的实际编号变化而变化。简单的搜索后&#xff0c;找到了一个方法&#xff0c;在此记录一下&#xff0c;以备后用。怎样在Word…

word参考文献交叉引用的多项引用,改逗号和破折号形式

word参考文献交叉引用的多项引用&#xff0c;如&#xff1a;[1][2][3]-->[1-3]&#xff0c;[1][3][4][5]-->[1,3-5] 1 引用2个参考文献2 引用三个&#xff08;及以上&#xff09;连续序号的参考文献总结 1 引用2个参考文献 1.1 按步骤1&#xff0c;2&#xff0c;3&#…

Word中的参考文献引用

选中参考文献选择【段落】–》【段落编号】 最终效果 引用方法&#xff1a;单击【引用】–》【交叉引用】–》选择【插入】