对于变量来说,当被定义为final类型时,表示这个变量是不可改变的,也就保证了只会对它赋值一次,试图改变final变量的值,编译时会报错,所以,申明为final类型的数据类型通常被认为是不可变的数据类型。
但是,存在一种情况,“会使这种不可变数据类型被改变”
Java中新建一个类的对象通常是通过引用来实现的,这种引用会造成.“ 引用不变,但是引用所指向的值发生了改变”这种情况而编译时不会报错,所以final的一个缺点就暴露了:只能用来保证原始数据类型的实例变量不可变性,而无法用于引用类型的变量。
如果一个实例变量由final修饰,该变量的值(对某个对象的引用)就永远无法改变,它将永远指向同一个对象,但对象的值仍然是可变的
下面是一个例子:
package one;
/**
* 这个 例子用来测试“不可变性的另一个缺点在于,final非常不幸的只能用来保证原始数据类型的实例变量的不可变性,而无法用于引用变量”
*
* 在这个例子中,final类型数据coords是一个引用变量,在构造方法中指向了传入的double型数据mainTest
* 但是原始double型数据mainTest并不是final类型数据,所以在改变mainTest后,引用类型数据coords本身没有改变
* 仍然是指向的mainTest,所以这样就造成了两次输出coords的结果不一样
*
*/
public class TestFinal {
// 申明一个double型数组变量,修饰为final类型
private final double[] coords;
// 构造方法,赋值给变量,使得coords引用参数"地址"
public TestFinal(double[] a) {
coords = a;
}
public static void main(String[] args) {
// 创建一个double型数组,并初始化
double[] mainTest = { 1.0, 2.2 };
// 创建一个本类的实例对象
TestFinal test = new TestFinal(mainTest);
// 输出显示实例对象中的一个值,这时,因为在构造方法中设定好了coords是引用的mainTest,所以coords[1]就是mainTest[1]的值
System.out.println(test.coords[1]);
// 这里改变了原始数据中的值,但是coords对mainTest的引用不变
mainTest[1] = 3.3;
// 所以对于引用的值的显示会是原始数据中的值
System.out.println(test.coords[1]);
}
}