Java基于final修饰数据过程解析
这篇文章主要介绍了Java基于final修饰数据过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
final是Java中的一个重要关键字,它可以修饰数据、方法和类,本篇将从final修饰的数据角度对final做出总结。
final修饰的数据代表着:永远不变。意思是,一旦你用final修饰一块数据,你之后就只能看看它,你想修改它,没门。
我们不希望改变的数据有下面两种情况:
永不改变的编译时常量。
//编译时知道其值 privatefinalintvalueOne=9;
在运行时(不是编译时)被初始化的值,且之后不希望它改变。
//在编译时不能知道其值 privatefinalinti4=rand.nextInt(20);
设置成常量有啥好处呢?
很简单,让编译器觉得简单,就是最大的好处。比如把PI设置成final,且给定值为3.14,编译器自然会觉得这个东西不会再被修改了,是足够权威的。那么,编译器就会在运行之前(编译时)就把这3.14代入所有的PI中计算,这样在真正运行的时候,速度方面当然会快一点。
有初始值的final域
即声明为final且当场就给定初始值的域。
privatefinalintvalueOne=9;
final+基本数据类型
final修饰的基本数据类型变量存储的数值永恒不变。
/*基本类型变量*/ //带有编译时数值的final基本类型 privatefinalintvalueOne=9; privatestaticfinalintVALUE_TWO=99; publicstaticfinalintVALUE_THREE=39; //!false:fd1.valueOne++; //!false:fd1.VALUE_TWO++; //!false:fd1.VALUE_THREE++;
康康上面醒目的三句false语句,很好地印证了我们之前说的:数值不让改!!!
需要注意的是,按照惯例,下面是定义常量的典型方式:
//典型常量的定义方式 publicstaticfinalintVALUE_THREE=39;
- public修饰符使其可被用于包之外。
- static使数据只有一份。
- final表示其无法被更改
- 名称全为大写英文字母,以下划线隔开。
final+引用数据类型
我们之前说过,基本类型存数值,引用类型存地址值。那么既然final+基本数据类型不让改数值,聪明的我们稍微一联想就明白,final+引用数据类型就是不让你改变量存储实际对象的地址值啦。(也就是不能再让它指向新的对象,很专一)
privateValuev1=newValue(1); privatefinalValuev2=newValue(22); privatestaticfinalValueV_3=newValue(333); //引用变量并不是常量,存储地址可以改变 fd1.v1=newValue(10); //v2是引用变量,final修饰之后表示地址不能改变,但是实际对象的值是可以改变的 fd1.v2.i++; //!false:fd1.v2=newValue(3); //V_3与v2类似,是静态和非静态的区别,下面会说明 fd1.V_3.i++; //!false:fd1.V_3=newValue(10); }
通过例子,确实也证明上面所说,一个以final修饰的引用数据类型变量,无法再指向一个新的对象,因为它所存储的地址值已经无法被更改,但是并不影响它指向的实际对象。就拿一个比较典型的引用类型来举例,我们知道数组就是一种典型的引用类型,数组的引用变量存储的是数组再堆中的地址,堆中存放的就是数组每个索引的数值。
/*引用变量之数组*/ privatefinalint[]a={1,2,3,4,5,6};
引用变量a被指定为final,所以它里面的地址值不能再改,也就无法再让它指向一个新的数组。
//!false:fd1.a=newint[]{2,3,4,5,6,7}; for(inti=0;i但是,它指向的数组里的每个元素却可以改动,因为数组中的元素并没有任何的限定。
final与staticfinal
privatefinalinti4=rand.nextInt(20); staticfinalintINT_5=rand.nextInt(20); System.out.println(fd1);//fd1:i4=15,INT_518 FinalDatafd2=newFinalData("fd2"); System.out.println(fd2);//fd2:i4=13,INT_518 FinalDatafd3=newFinalData("fd3"); System.out.println(fd3);//fd3:i4=1,INT_5=18上面示例分别创建了三个不同的对象,对其final和finalstatic进行测试。
- 需要明确的是,两者都以final修饰,都不能被改变。
- 三个对象的i4值,没有用static修饰,不相同且不能改变。
- 而INT_5的值因为被static修饰,在类加载时已经被初始化,不随对象改变而改变。
空白final域
即声明为final却没有给定初始值的域。
privatefinalStringid;//空白final
如果只有上面的这句,编译器会报错,因为它没有初始化。
Variable'id'mightnothavebeeninitialized
所以,若定义了空白final域,一定记得在构造器中给它赋值!(必须在域的定义处或者每个构造器中以表达式对final进行赋值,因为系统不会为final域默认初始化)
//在构造器中为空白final域赋初值 publicFinalData(){ id="空白final默认id"; } publicFinalData(Stringid){ this.id=id; }不要试图在初始化之前访问域,不然会报错。
final让域可以根据对象的不同而不同,增加灵活性的同时,又保留不被改变的特性。
final修饰的参数
基本数据类型的参数
类似地,就是传入的参数不让改,只让读,这一点很好理解。
publicintfinalParamTest(finalinti){ //!false:i++; //不让改,只让读 returni+1; }但是,我又新增了许多测试,分别定义四种不同的参数传入该方法,发现传入param0和param1编译会报错。(非常疑惑,这部分书上没提,查了许多资料也没有理解清楚,希望大牛可以评论区指点迷津)
/*检测传入参数*/ intparam0=5; finalintparam1=10; staticfinalintPARAM_2=15; staticintparam3=20; //!false:System.out.println(fd1.finalParamTest(param0)); //!false:System.out.println(fd1.finalParamTest(param1)); //non-staticfield'param1'cannotbereferencedfromastaticcontext System.out.println(fd1.finalParamTest(PARAM_2)); System.out.println(fd1.finalParamTest(param3)); /*为什么形参列表里的参数用final修饰,但是用final修饰的param1无法传进去, 一定要static修饰?*/引用数据类型的参数
publicvoidfinalReferenceTest(finalFinalDatafd){ //!false:fd=newFinalData(); //不能再指向新的对象,存储地址不准变 fd.param0++; }还是类似,不可以让这个引用类型的参数再指向新的对象,但是可以改变其实际指向对象的值。
最后的最后,下面的代码是根据《ThinkinginJava》中的示例,结合自己的思想,将各个板块融合而成的超级无敌测试代码,冲冲冲!
packagecom.my.pac16; importjava.util.Arrays; importjava.util.Random; /** *@autherSummerday */ classValue{ inti;//packageaccess publicValue(inti){ this.i=i; } } /*final域在使用前必须被初始化:定义时,构造器中*/ publicclassFinalData{ /*检测传入参数*/ intparam0=5; finalintparam1=10; staticfinalintPARAM_2=15; staticintparam3=20; privatestaticRandomrand=newRandom(47); privatefinalStringid;//空白final publicFinalData(){ id="空白final默认id"; } publicFinalData(Stringid){ this.id=id; } //带有编译时数值的final基本类型 privatefinalintvalueOne=9; privatestaticfinalintVALUE_TWO=99; //典型常量的定义方式 publicstaticfinalintVALUE_THREE=39; //在编译是不能知道其值 privatefinalinti4=rand.nextInt(20); staticfinalintINT_5=rand.nextInt(20); privateValuev1=newValue(1); privatefinalValuev2=newValue(22); privatestaticfinalValueV_3=newValue(333); privatefinalint[]a={1,2,3,4,5,6}; @Override publicStringtoString(){ returnid+":"+"i4="+i4+",INT_5="+INT_5; } publicintfinalParamTest(finalinti){ //!false:i++; //不让改,只让读 returni+1; } publicvoidfinalReferenceTest(finalFinalDatafd){ //!false:fd=newFinalData(); //不能再指向新的对象,存储地址不准变 fd.param0++; } publicstaticvoidmain(String[]args){ FinalDatafd1=newFinalData("fd1"); /*基本类型变量*/ //!false:fd1.valueOne++; //!false:fd1.VALUE_TWO++; //!false:fd1.VALUE_THREE++; /*引用变量*/ fd1.v1=newValue(10); fd1.v2.i++ //!false:fd1.v2=newValue(3); System.out.println("fd1.v2.i=["+fd1.v2.i+"]"); //!false:fd1.V_3=newValue(10); fd1.V_3.i++; System.out.println("fd1.V_3.i=["+fd1.V_3.i+"]"); /*引用变量之数组*/ System.out.println("before:fd1.a[]="+Arrays.toString(fd1.a)); /*数组引用变量a是final修饰, 但是不代表它指向的数据值是final, 而是a存储的地址值不能改变 */ //!false:fd1.a=newint[]{2,3,4,5,6,7}; for(inti=0;i文章如有理解错误或叙述不到位,欢迎大家在评论区加以指正。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。