版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sup_chao/article/details/84848237
一、基本概念
以下所有的内容都是基于内存地址来说的。
不可变数据类型: 当该数据类型的对应变量的值发生了改变,那么它对应的内存地址也会发生改变,对于这种数据类型,就称不可变数据类型。
可变数据类型 :当该数据类型的对应变量的值发生了改变,那么它对应的内存地址不发生改变,对于这种数据类型,就称可变数据类型。
总结:不可变数据类型更改后地址发生改变,可变数据类型更改地址不发生改变
二、从Java的String&StringBuilder中看差别
这里引入Snapshot diagrams,不清楚的可以点击Snapshot diagrams跳转到下面查看。
String:不可变数据类型
StringBuilder:可变数据类型
-
更改对象的值
不可变数据类型是在重新将引用指向一个新地址,新地址中为更改后的值。 可变数据类型则在原来的地址上直接更改对象值。String s = "a"; s = 'ab'; StringBuilder sb = "a"; sb = "ab";
-
一个地址被多个对象引用时
String s = "a"; s = 'ab'; StringBuilder sb = "a"; sb = "ab"; String t = s; t = t + "c"; StringBuilder tb = sb; tb.append("c");
-
其他差别
不可变数据类型:对其修改会产生大量的临时拷贝(需要垃圾回收)
可变数据类型:最少化拷贝以提高效率,可以共享数据
三、可变数据使用风险
- 传参传递可变数据类型
//计算List所有数据绝对值之和 //风险:更改了list中的值 public static int sumAbsolute(List<Integer> list) { for(int i = 0; i < list.size(); i++) list.set(i,Math.abs(list.get(i))); return sum(list); }
- 返回可变数据类型
//生成聚会时间 //风险:在更改partyDate时同样会更改answer的值 private static Date answer = null; public static Date startOfString() { if(answer == null) answer = newDate(); return answer; } public static void partyPlanning() { Date partyDate = startOfString(); partyDate.setMonth(partyDate.getMonth()+1); }
四、保障可变数据类型数据的安全
通过防御式拷贝,给客户端返回一个全新的Date对象,例如上图中第二个例子。
return new Date(groundhogAnswer.getTime());
五、(补充)Snapshot diagrams
Snapshot diagrams:
用于描述程序运行时内部状态的快照图。 其作用:
(1)便于程序员之间的交流
(2)便于刻画各类变量随时间变化的过程
(3)便于解释设计思路
- 基本数据类型
- 对象类型
- 不可变类型的对象
不可变对象:用双线椭圆
可变对象:用单线椭圆
- 不可变的引用
即带final关键字的引用,用双线箭头
- 其他
不可变引用指向可变引用final StringBuilder sb = new StringBuilder("abc"); sb.append("d"); //引用是不可变的,但指向的值却可以是可变的 sb = new StringBuilder("e"); //编译阶段出错:The final variable sb cannot be assigned System.out.println(sb);
6. 查bug1
7. 查bug2