Java中的可变类与不可变类
可变类与不可变类
在学习软件构造课程时,一直对可变类与不可变类没有一个很清晰的认识,有些疑问,类似于:如果不可变类中是因为没有变值器才让他不可变的话,那么getter后得到的对象也是不可变类中的对象,那么获得之后不就是可以对其改变了吗,为什么不会影响不可变类中的对象呢?
要弄清这个问题,首先要理解可变数据类型与不可变数据类型
可变数据类型与不可变数据类型
可变数据类型:
对于一个可变数据类型的变量,当其值发生变化时,和原来的变量采用的是一个地址空间,即在原内存的基础上,对值进行的修改
不可变数据类型:
与可变数据类型相反,只要变量的值发生了改变,那么其地址空间也发生了变化,可以理解为将变量的“指针”指向了一个新的地址,这个新的地址里存储的就是新的值
下面是用图形来展示:
可变类与不可变类
理解了可变数据类型与不可变数据类型后,再来看可变类与不可变类
根据上面的可变与不可变数据类型,我们又有了新的想法,可变类是没什么疑问了,对于不可变类中,如果采用了可变数据类型的变量和不可变类型数据的变量都利用getter获取他们的值,这样能否利用getter获得的值对其修改呢?下面是实际的尝试:
不可变类,可变数据类型变量:
public class unmutableADT {
private StringBuffer str;
public unmutableADT(StringBuffer str) {
this.str = str;
}
public StringBuffer getter() {
return this.str;
}
}
public class tryness {
public static void main(String[] args) {
unmutableADT uta = new unmutableADT(new StringBuffer("AAA"));
System.out.println(uta.getter());
uta.getter().append("BBB");
System.out.println(uta.getter());
}
}
运行结果:
AAA
AAABBB
在这个例子中,利用的可变数据类型StringBuffer来进行测试,通过实验结果可以看出虽然unmutableADT中没有变值器,但是由于他的变量是可变数据类型,所以利用getter获得变量后即可利用其实可变数据类型的性质对其进行“隐秘的修改”
不可变类,不可变数据类型变量:
public class unmutableADT {
private String str;
public unmutableADT(String str) {
this.str = str;
}
public String getter() {
return this.str;
}
}
public class tryness {
public static void main(String[] args) {
unmutableADT uta = new unmutableADT("AAA");
System.out.println(uta.getter());
uta.getter().concat("BBB");
System.out.println(uta.getter());
}
}
运行结果:
AAA
AAA
在这个例子中,同样是对getter到的变量进行了链接操作,但是由于String是不可变数据类型,所以无法对其进行在原地址空间内的修改,即修改后的新值并不在str指向的地址空间内,所以str仍然对应原来的值
主要的内容已经说完了,下面额外尝试一些奇怪的想法
在写不可变类时经常会发现final的字样,那么final到底起到什么作用呢,我做了一些尝试
尝试1
final可不可以限制可变数据类型同样不可被修改?
public class tryness {
public static void main(String[] args) {
final StringBuffer str = new StringBuffer("AAA");
str.append("BBB");
System.out.println(str);
}
}
运行结果:
AAABBB
可见final不能阻止可变数据类型的修改
那么final到底限制了什么呢?
尝试2
public class tryness {
public static void main(String[] args) {
final String str;
str = "AAA";
str = "BBB"; //这行会报错
}
}
对于final限制的变量,只允许赋值一次,后面再进行赋值会导致报错,这也就是为什么不可变类中的变量总是习惯上加一个final
我的理解是:final限制了地址空间不可变,所以根据可变和不可变数据类型变量的性质就导致上面这样的情况,这也就解决了我在之前做“软件构造Lab2”是的疑问,其中有一个类中就是用final修饰了一个list,当时我的理解没有现在这样清晰,总是认为final修饰了list,那么list是不是就不能在加入元素了呢,现在看来是不对的,list加元素时本身的地址空间没变,所以final也就不是对list元素不可变的制约。
此篇文章只是我个人理解,如果有错误欢迎指出,感谢阅读!