在写scala的时候,常常不太明白Mutable and Immutable Collections的用法和区别。官方文档说得很清楚:
A mutablecollection can be updated or extended in place. This means you can change, add, or remove elements of a collection as a side effect. Immutable collections, by contrast, never change.
但是我们在用的时候很发现这两个并没什么异样。
一、摆例子,抛出疑惑
例子1-1:
object Test1 extends App() {
var map = new scala.collection.mutable.HashMap[Int, String];
map += (1 -> "1");
map += (2 -> "2");
map += (3 -> "3")
map += (4 -> "4");
map += (1 -> "5");
println(map.mkString("\n"));
}
结果:
1 -> 5
2 -> 2
3 -> 3
4 -> 4
例子1-2:
var map = new scala.collection.immutable.HashMap[Int, String];
结果:
1 -> 5
2 -> 2
3 -> 3
4 -> 4
那么就奇怪了,其实对于这个基础好的码农一眼就知道了原因,所有的的猫腻都在+=这个操作符上,每次+=操作之后都会返回一个新的对象
也就是说这里共产生了6个map新对象。所以最后输出map的时候其实是最新的那个对象,原来的对象并没有变化。
那么问题是否这样呢?
二、深入验证假设。
例子2-1:
object Test1 extends App() {
var map = new scala.collection.mutable.HashMap[Int, String];
map += (1 -> "1");
map += (2 -> "2");
var tem = map;
tem += (1 -> "5");
println(map.mkString(" || "));
println("---------------")
println(tem.mkString(" || "));
}
结果:
2 -> 2 || 1 -> 5
---------------
2 -> 2 || 1 -> 5
奇怪的现象又来了,不是说好的+=操作每次都会返回新对象吗?这个试验的结果很明显最后的tem对象 += 的改变仍然会引起map对象的改变。
也就是说
tem += (1 -> "5");
根本不会引起一个新对象的产生。它们都指向同一个内存空间。fuck,我要砸键盘了!!!! 别急,请看第二个例子
例子2-2:
修改第一行为:
var map = new scala.collection.immutable.HashMap[Int, String];
结果:
1 -> 1 || 2 -> 2
---------------
1 -> 5 || 2 -> 2
好了,这个倒是符合我们当初的假设,暂时不砸键盘。
三、总结:
相信聪明的人一下子就能看出区别了。scala用心良苦,在+=这个操作符上为我们花了不少功夫。
+=这个操作符,如果操作的对象是可变的,它会自动调用对象的update方法(具体对象看具体操作),相当于更新或者追加的操作。
如果对象是不可变的,它就会返回一个新的对象。
问题扩展:为什么要花费精力弄明白可变与不可变对象的区别?(这个涉及到多线程安全,循环遍历等,具体自己上网查)