一、变量的改变
变量的改变分为两种:
1) 改变一个变量:将该变量指向另一个值的存储空间。
类似于C语言中的指针操作:p = &a;
2) 改变一个变量的值:将该变量当前指向的值的存储空间中写入一个新的值。
类似于C语言中的指针操作:*p = b;
二、不可变性与可变性
2.1 概念
不变数据类型:一旦被创建,其值不能改变。
引用类型的不变性:一旦确定其指向的对象,不能再被改变。
基本数据类型都是不变数据类型,而对象数据类型分为可变与不可变。
不变数据类型的对象:一旦被创建,始终指向同一个值/引用
可变数据类型的对象:拥有方法可以修改自己的值/引用
2.2 举例String与StringBuilder
2.2.1 String
String是一个典型的不可变类型。String类型的对象一旦被创建,它内部的值就不可改变了。
但是我们在实际编程中会写如下代码,这里s的值不是改变了吗?
String s = "a";
s = s.concat("b"); //s += "b"
实际上在这个例子中改变的并不是s的值,而是s这个变量本身,即它的指向。我们用snapshot diagram描述上述过程如下:
值为"a"的对象在创建后就不可变了,s只是保存了这个对象的首地址,当s的"值"改变时,要新建一个值为"ab"的对象,再将s指向新创建的对象。在这一过程中String对象保持不可变性。
2.2.2 StringBuilder
StringBuilder是与String相对应的可变数据类型,也能表示字符串。
以下是与上一小节同义的代码:
StringBuilder sb = new StringBuilder("a");
sb.append("b");
该过程的snapshot diagram如下:
我们能看到sb没有指向其它对象,而是将现指向的对象中的值改成"ab"。
三、final
在编程过程中,我们可以使用关键词final去声明某引用是不可变的。
final Person a = new Person("Ross");
a = new Person("Jack");
当我们写完上述代码,程序会报错,因为我们改变了a的引用,而a被final修饰,这种引用改变是不合法的。 这种错误检测属于静态类型检查。
以下是final的几种用法:
1) 修饰类,被修饰类无法派生子类。
2) 修饰变量:变量无法改变值/引用。
3) 修饰方法:方法无法被子类重写。