JAVA中的数据类型
不变性和可变性
改变一个变量:将该变量指向另一个值的存储空间
改变一个变量的值:将该变量当前指向的值的存储空间中写入一个新的值
不变性:重要设计原则
不变数据类型:一旦被创建,其值不能改变
如果是引用类型(指针),也可以是不变的:一旦确定其指向的对象,不能再被改变
要使引用不可变,请使用关键字final声明它:
final int n = 5;
final Person a = new Person(“Ross”);
如果编译器无法确定final变量不会改变,就提示错误,这也是静态
类型检查的一部分。
尽量使用final变量作为方法的输入参数、作为局部变量。
final表明了程序员的一种“设计决策”
注意:
final类无法派生子类
final变量无法改变值/引用(注意区别!)
final方法无法被子类重写
不变对象和可变对象的区别:
不变对象:一旦被创建,始终指向同一个值/引用
可变对象:拥有方法可以修改自己的值/引用
String是不可变类型的一个示例:
要在字符串的末尾添加某些内容,必须创建一个新的字符串对象:
StringBuilder是可变类型的一个示例。
它有删除字符串的部分、插入或替换字符等的方法。此类具有更改对象值的方法,而不仅仅是返回新值。
当只有一个引用指向该值,没有区别
有多个引用的时候,差异就出现了
可变类型的优点:
使用不可变类型,对其频繁修改会产生大量的临时拷贝(需要垃圾回收)
可变类型最少化拷贝以提高效率
使用可变数据类型,可获得更好的性能 ,也适合于在多个模块之间共享数据
既然如此,为何还要用不可变类型?
不可变类型更“安全”,在其他质量指标上表现更好
可变类型有风险:
传入可变类型:潜在风险可能改变输入参数的值,这种错误非常难于跟踪和发现
返回可变类型:需防御式拷贝, 大部分时候该拷贝不会被客户端修
改,可能造成大量的内存浪费。如果使用不可变类型,则节省了频繁复制的代价。
防御式拷贝的更多示例:
快照图作为代码级、运行时视图和时刻视图
Snapshot diagrams
快照图表示程序在运行时的内部状态—其堆栈(正在进行的方法及其局部变量)及其堆(当前存在的对象)。用于描述程序运行时的内部状态。
Primitive values 原始值基本类型的值
-原始值由裸常数表示。传入的箭头是对变量或对象字段中的值的引用。
Object values 对象类型的值
-对象值是按其类型标记的圆。
-当我们要显示更多详细信息时,我们会在其中写入字段名,箭头指向它们的值。有关更多详细信息,这些字段可以包括其已声明的类型。
重分配和不可变值
例如,如果我们有一个字符串变量s,我们可以将它从“a”的值重新分配为“ab”字符串
s=“a”;
s=+“b”;
不可变对象:用双线椭圆
可变的值
相比之下,StringBuilder(一个内置的Java类)是一个表示一个字符串的可变对象,它有更改对象值的方法:
StringBuilder sb=StringBuilder(“a”);
sb.append(“b”);
不可重新分配/不可变的引用
Java还给了不可变的引用:分配一次而不会重新分配的变量。要使引用不可变,请声明关键字
final int n=5;
在快照图中,不可重新分配的引用(final)用双箭头表示。
引用是不可变的,但指向的值却可以是可变的
可变的引用,也可指向不可变的值