阅读材料一:静态检查>7.可变值对比重赋值变量
Reading 1: Static Checking > Mutating Values Vs. Reassigning Variables
原文地址:https://courses.edx.org/courses/course-v1:MITx+6.005.1x+3T2016/courseware/Readings_Videos/01-Static-Checking/
可变值对比重赋值变量
画下运行时发生事情的图片对我们明白一些潜在问题来说很有帮助.快照图代表了一个程序运行时的状态.
图表1用其最简单的形式,一个快照图显示一个变量以及用一个剪头指向其值.一个值可能是一个基本变量比如说int,可以简单地写一个数字,又或者是一个对象例如String或者ArrayList,这用一个圆包裹着它的类型.一个对象的值往往有其内在的变量以及箭头指向其值.例如,在冰雹序列代码的某个从n=3开始的地方,一个快照图可能如上图所示.
尽管这门课图片的例子运用Java,这个标记可以用到其他任何现代的语言,例如Python,C++,Ruby.
快照图给了我们一个直观的方式去可视化改变变量和改变值的区别:
- 当你给一个变量赋值时,你在改变变量剪头的指向.你可以使它指向一个不同的值.
intn =3;n = 3*n + 1;n = n/2;
图表2- 当我们改变一个可变值的内容时--比如一个集合或者一个列表--你在改变一个值的内在引用.这称为改变值.
Listlist=newArrayList();list.add(3);list.add(5);list.set(0, 9);
图表3重赋值和不可变值
例如,我们有一个String类型的变量s,我们可以把它的值从'a'重赋值为'ab'.
String s ="a";
s = s +"b";
String是一个不可变类型的例子,一个类型其值至创造后再也不能改变.不可变性是本门课的一个主要的设计原则.我们将在阅读材料中更多的谈到这一点.
不可变对象(它们设计者的目的是用它们代表相同的值)在快照图中用两个边界表示,类似我们图表中的String类型.
可变的值
相反,StringBuilder(另一个Java自带的类型)是一个可变的对象代表了一串对象.它有方法去改变它的值.
StringBuilder sb =newStringBuilder("a");
sb.append("b");
图表5这两个快照图看起来很不一样,哪一个是好的:可变和不可变的差别在使代码远离bug的过程中扮演了重要的角色.
不可变引用
Java还给了我们不可变的引用:变量赋值了一次就不用再赋值了.为了引用不可变,用final关键词声明它:finalintn =5;
如果你的Java编译器不确定你的final变量将在运行时只赋值一次,它将产生一个编译错误.因此final给你了一个静态的不可变引用的检测.
在快照图中,一个不可变的引用将用双线的箭头.
图表6注意到我们可以有一个不可变的引用引用到一个可变的值.例如:final StringBuilder sb;这意味着这个StringBuilder的值可以改变,但是sb的箭头不会改变;它永远指向同一个StringBuilder对象.
我们可以永远有一个可变的引用到一个不可变的值.比如String s,s变量的值可以改变因为它可以重指向不同的对象.
在声明一个方法的参数和尽可能多的本地变量时,用final是一个很好的实践.类似变量的类型,这些声明是非常重要的文档,对读代码很有用以及编译器可以静态检测.
这里有我们的冰雹序列的两个变量:我们可以将它们声明为final吗?
图表7