当前位置: 首页 > 科技观察

添加Final可以防止它被修改吗?我太天真了

时间:2023-03-23 10:02:13 科技观察

本文转载自微信公众号《JerryCodes》,作者KyleJerry。转载本文请联系JerryCodes公众号。immutablefinal和immutable有什么关系总结什么是不可变要回答上面的问题,首先要知道什么是不可变(Immutable)。如果一个对象在创建后不能修改其状态,则该对象是“不可变的”。举个例子,比如下面的Person类:publicclassPerson{finalintid=1;finalintage=18;}如果我们创建一个person对象,里面会有两个属性,分别是id和age,由于都是final修饰的,所以person对象一旦创建,其中的所有属性,即id和age,都不能再改变了。如果我们要改变属性的值,就会报错。代码如下:publicclassPerson{finalintid=1;finalintage=18;publicstaticvoidmain(String[]args){Personperson=newPerson();//person.age=5;//编译错误,无法修改该值finalvariable}}例如,如果我们尝试改变person对象,例如将age更改为5,它将无法编译,因此像这样的person对象是不可变的,这意味着它的状态不能改变。当final修饰一个对象时,它只是指不可变性!这里有一个很重要的点需要注意,就是当我们用final修饰一个指向对象类型(而不是指向8种基本数据类型,比如int等)的变量时,那么final的函数只是保证这个变量的引用是不可变的,对象本身的内容还是可以改变的。下面我们对此进行解释。final修饰的变量,意味着一旦赋值就不能再修改,即只能赋值一次。如果我们再次尝试给一个已经被final修改过的变量赋值,就会报编译错误。我们用下面的代码来说明:/***说明:final变量一旦赋值,就不能修改*/publicclassFinalVarCantChange{privatefinalintfinalVar=0;privatefinalRandomrandom=newRandom();privatefinalintarray[]={1,2,3};publicstaticvoidmain(String[]args){FinalVarCantChangefinalVarCantChange=newFinalVarCantChange();//finalVarCantChange.finalVar=9;//编译错误,不允许修改final变量(基本类型)//finalVarCantChange.random=null;//编译错误,不允许修改final变量(对象)//finalVarCantChange.array=newint[5];//编译错误,不允许修改final变量(数组)}}我们首先创建了一个变量int类型和一个Random类型的变量,还有一个数组,它们都是final修饰的;然后尝试修改它们,比如把int变量的值改成9,或者把random变量设置为null,或者给array重新赋一个内容,这些代码都不会通过。这就证明了“被final修饰的变量,一旦赋值就不能被修改”,这个规则对于基本类型的变量是没有歧义的,但是对于对象类型来说,final实际上只是保证了这个变量的引用是不可变的,而对象本身仍然是可变的。这同样适用于数组,因为数组在Java中也是对象。那我们举个例子看看下面Java程序的输出:classTest{publicstaticvoidmain(Stringargs[]){finalintarr[]={1,2,3,4,5};//注意数组arr是最终的for(inti=0;ilessons=newHashSet<>();publicImmutableDemo(){lessons.add("第一讲:为什么线程只有一种实现方式?");lessons.add("02讲:如何正确停止线程?为什么volatile标志位的stop方法不对?");lessons.add("03讲:线程如何在6种状态之间切换?");}publicbooleanisLesson(Stringname){returnlessons.contains(name);}}在这个类中,有一个final的private修饰的Set对象叫lessons,是一个HashSet;然后我们在构造函数中添加了HashSet三个值,分别是01、02、03讲的主题;类中还有一个方法isLesson,判断传入的参数是否属于本课前3课的题目。isLesson方法是利用lessons.contains方法判断,如果包含则返回true,否则返回false。这是这个类的内容,没有其他额外的代码。在这种情况下,lessons虽然是Set类型,虽然是对象,但是对于ImmutableDemo类的对象来说是不可变的。因为lessons对象是final私有的,引用不会改变,外部无法访问,并且ImmutableDemo类没有任何方法可以修改lessons中包含的内容,只是在其中添加了初始值构造函数中的lessons,所以一旦创建了ImmutableDemo对象,也就是一旦执行了构造方法,后面就没有机会修改lessons中的数据了。对于ImmutableDemo类来说,它只有这么一个成员变量,而这个成员变量一旦构造就不能改变,所以这个ImmutableDemo类的对象是不可变的,是一个很好的“包含对象”,其成员变量是类的对象类型是不可变的”示例。综上所述,我们首先介绍了什么是不可变性,然后介绍了当一个对象类型的变量被final修饰时,只能保证它的引用不变,而对象内容本身还是可以改变的。仅仅用final修饰所有的成员变量并不意味着类的对象是不可变的。