为了便于理解,可以思考这样一个问题:改变一个变量和改变一个变量的值,有何区别?

从C语言的角度来看,改变一个变量是指改变变量指向的存储空间,改变“指针”的值;如

char c = 'a';
char *p = &c;	//p是指向字符类型的指针,p指向变量c,p的值的是变量c的地址空间,而该地址空间存储字符a
char *q = 'b';	//q同p一样,但q的值与p的值不同,且q的值所对应的地址存储的字符是b
p = q;	//将q对应的地址赋值给p,改变了p变量

(注:原理一致,但在Java中无指针的概念,具体见下文)
而改变一个变量的值,就是改变一个变量的内部存储的值,如

int a = 10;	//变量a存储值为10
a = 5;	//变量a对应的存储空间不变,地址不变,但是该地址内部存储的值由10变为5,改变了a的值

在C语言中理解可变与不可变是不完全不充分的,为了充分理解我们回到Java中。然而,在Java中抛弃了指针的概念,减少了很多麻烦与复杂,在Java中我们又如何理解可变与不可变呢

不变数据类型与可变数据类型

首先明确一点,可变与不可变是针对变量的值来说的

不变数据类型是指一旦被创建,其值就不能改变的数据类型;
如果是引用类型,也可以是不变的:一旦确定所引用的对象,就不能改变指向其它对象

为了使一个引用变得不可变,可以加上关键字final

final int m = 0;	//原本可变的int变量a不再能改变引用
m = 1;	//在编译阶段会报错,因为m不可变,却被又赋值10

final还有其它作用:

  1. 放于方法前,final方法不能被子类重写
  2. 放于类前,final类无法派生子类

可变数据类型,对于基本数据类型来说,都是可变的(通过赋值可变),对于一些可变对象,它们内部有相关方法实现‘可变’

可以通过一个例子来说明一下:

String s = "ab";	//String对象是不可变的,创建之后指向的值或引用不变
StringBuilder sb = "ab";	//StringBulider对象可变,内部有相关方法实现
s.concat("c");	//此时s指向的字符串不变,仍为ab,但是产生结果abc被创建为新的字符串
sb.append("c");	//sb可变,指向地址空间未变,在原来地址中存储值由ab变为abc
s = s.concat("c");	//将创建新的字符串abc对应的地址赋值给s
					//可变不可变是针对存储空间对应的值来说的,原来存储空间仍存放着ab					  //值未变,然而s指向的地址空间可以变,这是s指向地址空间存储值为abc

二者的使用

在不同场景对二者有不同的使用

不可变数据类型在使用过程中,如果对其有大量的修改,就会产生大量的拷贝,造成内存资源的浪费,此时使用可变数据类型可以大大减少浪费,提高效率

String s = "";
StringBuilder sb = "";
for (int i = 0; i < 1000 * 1000; i++){
	s = s.concat("a");	//s总共指向1000000个地址,内存浪费
}
for (int i = 0; i < 1000 * 1000; i++){
	sb.append("a");	//sb只使用了一个内存地址,减少内存浪费
}

然而,使用可变数据类型是在一定情况下有风险的

public class Person{
	private List<String> person = new ArrayList<>();
	public void Person(List<String> list){
		this.list = list;
	}
	public List<String> getlist(){
		return this.list;
	}
}
···
	Person a = Person(list1);
···
	List<String> list = a.getlist;

在上面的情况中,我们实现Person类想让其内部实现对外不可见,且它内部的list不应该被外部所影响,然而我调用它内部getlist方法,将其内部list直接传送到外面,而且List是可变的,我在外面对其进行操作,同样也是对Person a内部list的操作,可能造成破坏。

对于上述情况。可以采取防御式拷贝,将新生成一份同样的数据,值相同,但不指向相同的地址空间

从上面可以看出,可变数据类型是不安全的。

综上,对于我们的实现来说,要对安全和内存的两个指标进行权衡,从而采取不同实现的数据类型

[========]
在后续的复习中,发现本文中的一个错误,在学习ADT抽象数据类型中,认识到基本数据类型是不可变的

以int为例

int a = 5;	//对应操作的creator,从无到有的产生一个int型变量
int b = 1;
a = a + b;	//对应操作的producer,从一个存在的变量产生新的
if (a == 6){
	//对应于操作的observer,观察变量a的值,是否与6相等
	b = 0;
}
	//基本数据类型不可变,无mutator

再看下面例子:

final m = 0;
m = 1;

这里final将m的引用不可变,m只能指向对于整数0对应地址的引用

而再次改变m的引用,让其指向整数1的地址空间,编译器则会报错

java中 可变数据结构 java中哪个数据类型可变_List

认真复习,反复复习,会有很多更深层次的理解

祝愿高考学子勇往直前,高考顺利!