Java可变类型与不可变类型
一、可变类型(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。
不可变类型较为呆板,当需要频繁修改变量值时,可能会产生大量的内存垃圾;但是安全系数高,数据不会被篡改。
选择可变与不可变类型,就是在效率与安全之间做折中,需要依据场合来判断。
Java可变类型与不可变类型相关推荐
- java中可变类型,不可变类型,不可变引用,不可变封装
一.可变类型与不可变类型 不可变数据类型: 当该数据类型的对应变量的值发生了改变,那么它对应的内存地址也会发生改变,对于这种数据类型,就称不可变数据类型. 可变数据类型 :当该数据类型的对应变量的值发 ...
- 浅析java中可变类型和不可变类型
一.可变数据类型和不可变数据类型 1.首先看一下二者的概念: 不可变数据类型: 当该数据类型的对应变量的值发生了改变,那么它对应的内存地址也会发生改变,对于这种数据类型,就称为不可变数据类型. 可变数 ...
- Java中的可变类型与不可变类型
一.可变对象与不可变对象 Java中某些对象是可变的(mutable),它们有改变内部值的方法.例如,一个StringBuilder对象有办法来改变字符串内部的字符,等等. StringBuilder ...
- python中哪些类型数据是不可变的_python的可变与不可变数据类型
首先,我们需要知道在python中哪些是可变数据类型,哪些是不可变数据类型.可变数据类型:列表list和字典dict:不可变数据类型:整型int.浮点型float.字符串型string和元组tuple ...
- Python:python中的可变类型和不可变类型
Python的基本数据类型大致可分为6类: 1.Number(数字)(bool布尔类型.int整型.float浮点型.complex复数等都归为Number数字类型) 2. String(字符串) 3 ...
- Python的可变类型和不可变类型
可变类型与不可变类型 1.可变类型,值可以改变: 列表 list 字典 dict set (没有value的字典) 2.不可变类型,值不可以改变: 数值类型 int, long, bool, flo ...
- python不可变的列表被称为_【Python学习】可变类型和不可变类型
一.可变类型与不可变类型的特点 1.不可变数据类型 不可变数据类型在第一次声明赋值声明的时候, 会在内存中开辟一块空间, 用来存放这个变量被赋的值, 而这个变量实际上存储的, 并不是被赋予的这个值, ...
- Python当中的a += a 与 a = a + a 的区别,可变类型与不可变类型的数据类型,引用传参...
a += a 与 a = a + a 的区别 可变类型a = a + a 的示例 In [58]: a = [11,22]In [59]: id(a) Out[59]: 140702917607688 ...
- python中什么可变_Python中的可变类型与不可变类型
Python基础知识,自己写一写比较不容易忘 Python的每个对象都分为可变和不可变,主要的核心类型中,数字.字符串.元组是不可变的,列表.字典是可变的. 对不可变类型的变量重新赋值,实际上是重新创 ...
最新文章
- 一文读懂比特币现金(BCH)
- MySQL 基础 ———— 视图的应用与总结
- python制作图片墙_利用python生成照片墙的示例代码
- 微信占用空间太大,删除又担心工作相关聊天记录,有啥好办法没?
- 第一个spring冲刺团队贡献分(80分满分)
- 河南理工大学计算机软件考研857数据结构
- Altium Designer 17 安装破解版详细教程
- Linux系统Anaconda下载安装教程
- 计算机毕业设计之流浪宠物管理系统
- html5库存管理,库存管理的基本方法
- 【OR】YALMIP大M法和凸包
- Android xUtils框架最全使用详解
- UMD格式与解析详解
- C#自定义控件添加到工具箱:
- Quartz 定时任务管理
- 高颜值游戏蓝牙耳机初体验,2020新款低延迟蓝牙耳机测评推荐
- 面包店利用拼团模式面包免费送-月销售30万 !
- linux串口特殊字符不能接收
- 你想要的宏基因组-微生物组知识全在这(2023.01)
- 我炒股十几年了,随着股龄的增长,对股市的操作也越来越得心应手。现在,股票年年都能赢利