final修饰的变量
被final修饰的实例变量必须显式指定初始值,而且只能在如下3个位置指定初始值.
1.定义final实例变量时指定初始值;
2.在非静态初始化块中为final实例变量指定初始值;
3.在构造器中为final实例变量指定初始值.
对于普通实例变量,Java程序可以对它执行默认的初始化,也就是将实例变量的值指定为默认的初始值0或null;但对于final实例变量,则必须由程序显式指定初始值.
package com.lic.array;
public class FinalInstanceVaribaleTest {
public static void main(String[] args) {
FinalInstanceVaribaleTest fiv = new FinalInstanceVaribaleTest();
System.out.println(fiv.var1);
System.out.println(fiv.var2);
System.out.println(fiv.var3);
}
// 定义final实例变量时赋初始值
final int var1 = "疯狂Java讲义".length();
final int var2;
final int var3;
// 在初始化块中为var2赋初始值
{
var2 = "轻量级Java EE企业应用实战".length();
}
// 在构造器中为var3赋初始值
public FinalInstanceVaribaleTest(){
this.var3 = "疯狂XML讲义".length();
}
}
上面的程序定义了3个final修饰的实例变量.var1,var2,var3,分别在定义是时为var1赋初始值,在初始化块中为var2指定初始值,在构造器中为var3指定初始值.但是经过编译器的处理,这三种方式都会抽取到构造器中赋初始值.如果使用javap工具来分析:
Compiled from "FinalInstanceVaribaleTest.java"
public class com.lic.array.FinalInstanceVaribaleTest {final int var1;final int var2;final int var3;public static void main(java.lang.String[]);Code:0: new #1 // class com/lic/array/FinalInstance
VaribaleTest3: dup4: invokespecial #2 // Method "<init>":()V7: astore_18: getstatic #3 // Field java/lang/System.out:Ljava/
io/PrintStream;11: aload_112: getfield #4 // Field var1:I15: invokevirtual #5 // Method java/io/PrintStream.printl
n:(I)V18: getstatic #3 // Field java/lang/System.out:Ljava/
io/PrintStream;21: aload_122: getfield #6 // Field var2:I25: invokevirtual #5 // Method java/io/PrintStream.printl
n:(I)V28: getstatic #3 // Field java/lang/System.out:Ljava/
io/PrintStream;31: aload_132: getfield #7 // Field var3:I35: invokevirtual #5 // Method java/io/PrintStream.printl
n:(I)V38: returnpublic com.lic.array.FinalInstanceVaribaleTest();Code:0: aload_01: invokespecial #8 // Method java/lang/Object."<init>":
()V4: aload_05: ldc #9 // String 疯狂Java讲义7: invokevirtual #10 // Method java/lang/String.length:()
I10: putfield #4 // Field var1:I13: aload_014: ldc #11 // String 轻量级Java EE企业应用实战16: invokevirtual #10 // Method java/lang/String.length:()
I19: putfield #6 // Field var2:I22: aload_023: ldc #12 // String 疯狂XML讲义25: invokevirtual #10 // Method java/lang/String.length:()
I28: putfield #7 // Field var3:I31: return
}
从上面分析结果可以看出:final实例变量必须显式地被赋初始值,而且本质上final实例变量只能在构造器中被赋初始值.当然,就程序员变成来说,还可在定义final实例变量时指定初始值,也可以初始化块中为final实例变量指定初始值,但它们本质上是一样的.除此之外,final实例变量将不能被再次赋值.
对于final类变量而言,同样必须显式指定初始值,而且final类变量只能在2个地方指定初始值:
1.定义final类变量时指定初始值;
2.在静态初始化块中为final类变量指定初始值.
package com.lic.array;public class Demo22 {// 定义final类变量时赋初始值final static int var1 = "疯狂Java讲义".length();final static int var2;// 在静态初始化块中为var2赋初始值static{var2 = "轻量级Java EE企业应用实战".length();}public static void main(String[] args) {System.out.println(Demo22.var1);System.out.println(Demo22.var2);}}
上面程序中定义了2个final类变量var1和var2,在定义var1时为其赋初始值,在静态初始化块中为var2指定初始值.需要指出的是,经过编译器的处理,这2中方式都会被抽取到静态初始化块中赋初始值.如果使用javap工具来肥西改程序:
Compiled from "Demo22.java"
public class com.lic.array.Demo22 {static final int var1;static final int var2;public com.lic.array.Demo22();Code:0: aload_01: invokespecial #1 // Method java/lang/Object."<init>":
()V4: returnpublic static void main(java.lang.String[]);Code:0: getstatic #2 // Field java/lang/System.out:Ljava/
io/PrintStream;3: getstatic #3 // Field var1:I6: invokevirtual #4 // Method java/io/PrintStream.printl
n:(I)V9: getstatic #2 // Field java/lang/System.out:Ljava/
io/PrintStream;12: getstatic #5 // Field var2:I15: invokevirtual #4 // Method java/io/PrintStream.printl
n:(I)V18: returnstatic {};Code:0: ldc #6 // String 疯狂Java讲义2: invokevirtual #7 // Method java/lang/String.length:()
I5: putstatic #3 // Field var1:I8: ldc #8 // String 轻量级Java EE企业应用实战10: invokevirtual #7 // Method java/lang/String.length:()
I13: putstatic #5 // Field var2:I16: return
}
上面程序为final类变量赋初始值.可以看到,var1,var2两个类变量的赋初始值过程都是放在静态初始化块内完成的.由此可见,final类变量必须显式地被赋初始值,而且本质上final实例变量只能在静态初始化块中被赋初始值.当然就程序员编程来说,还可在定义final类变量时指定初始值.也可以在静态初始化块中为final类变量指定初始值,但它们本质上是一样的.除此之外,final类变量将不能被再次赋值.
final修饰局部变量的情形则比较简单----Java本来就要求局部变量必须被显式地赋初始值,final修饰的局部变量一样需要被显式的赋初始值.与普通初始变量不同的是:final修饰的局部变量被赋初始值之后,以后再也不能对final局部变量重新赋值.
经过上面介绍,大致可以发现final修饰符的第一个简单功能:被final修饰的变量一旦被赋初始值,final变量的值以后将不会被改变.
除此之外,final修饰符还有一个功能.
package com.lic.array;public class Demo23 {public static void main(String[] args) {// 通过Price的INSTANCE访问currentPrice实例变量System.out.println(Price_23.INSTANCE.currentPrice);// 显式创建Price实例Price_23 p = new Price_23(2.8);// 通过显式创建的Price实例访问currentPrice实例变量System.out.println(p.currentPrice);}}
class Price_23{// 类成员是Price实例final static Price_23 INSTANCE = new Price_23(2.8);// 再定义一个类变量final static double initPrice = 20;// 定义该Price的currentPrice实例变量double currentPrice;public Price_23(double discount){// 根据静态变量计算实例变量currentPrice = initPrice - discount;}
}
你猜输出啥?
很明显,这是程序中增加了final修饰符的缘故.再次使用javap工具来分析下:
Compiled from "Demo23.java"
class com.lic.array.Price_23 {static final com.lic.array.Price_23 INSTANCE;static final double initPrice;double currentPrice;public com.lic.array.Price_23(double);Code:0: aload_01: invokespecial #1 // Method java/lang/Object."<init>":()V4: aload_05: ldc2_w #3 // double 20.0d8: dload_19: dsub10: putfield #5 // Field currentPrice:D13: returnstatic {};Code:0: new #2 // class com/lic/array/Price_233: dup4: ldc2_w #6 // double 2.8d7: invokespecial #8 // Method "<init>":(D)V10: putstatic #9 // Field INSTANCE:Lcom/lic/array/Price_23;13: return
}
如果不使用final修饰程序中的initPrice类变量,看看javap的分析结果
Compiled from "Demo23.java"
class com.lic.array.Price_23 {static final com.lic.array.Price_23 INSTANCE;static double initPrice;double currentPrice;public com.lic.array.Price_23(double);Code:0: aload_01: invokespecial #1 // Method java/lang/Object."<init>":()V4: aload_05: getstatic #2 // Field initPrice:D8: dload_19: dsub10: putfield #3 // Field currentPrice:D13: returnstatic {};Code:0: new #4 // class com/lic/array/Price_233: dup4: ldc2_w #5 // double 2.8d7: invokespecial #7 // Method "<init>":(D)V10: putstatic #8 // Field INSTANCE:Lcom/lic/array/Price_23;13: ldc2_w #9 // double 20.0d16: putstatic #2 // Field initPrice:D19: return
}
对比上面两个输出结果,不难发现当使用final修饰符变量时,如果定义该final类变量时指定了初始值,而且该初始值可以在编译时就被确定下来,系统将不会在静态初始化块中对该类变量赋初始值,而将是在类定义中直接使用该初始值代替该final变量.
对于一个使用final修饰的变量而言,如果定义该final变量时就指定初始值,而且这个初始值可以在编译时就确定下来,那么这个final变量将不再是一个变量,系统会将其当成"宏变量"处理.也就是说,所有出现该变量的地方,系统将直接把它当成对应的值处理.
对于上面的Price类而言,由于使用了final关键字修饰initPrice类变量,因此Price类的构造器中执行currentPrice = initPrice - discount; 代码时,程序直接会将initPrice替换成20.因此,执行该代码的效果相当于currentPrice = 20 - discount;.
final修饰的变量相关推荐
- final修饰的变量是引用不能改变还是引用的对象不能改变
我们都知道final修饰变量时 会变为常量,但是使 用final关键字修饰一个变量时,是引用不能变,还是引用的对象不能变? 下面让我们来看这段代码: [java] view plain copy /* ...
- final修饰的变量就是常量?
概念 什么是常量? 对于这个问题,可能很多人都可以脱口而出 : 用final修饰的变量是常量 ,或者是在编译时期定义好的字符串.(字符串常量) 但是这种说法是不严谨的,因为准确来说 : 常量是用fin ...
- final修饰的变量必须初始化吗?
final关键字的用法大家应该都知道. 修饰的类不能被继承. 修饰的方法子类可以使用,但是不能进行重写. 修饰的变量只能被赋值一次,引用不可变. 引用不可变的变量,只能被赋值一次.但是如果变量是对象, ...
- 关于final修饰的变量赋值的问题
一.赋值的方式 1.可以定义变量时直接赋值 2.可以在代码块中进行赋值(静态代码块和构造代码块) 3.可以再构造方法中进行赋值. 总结起来,就是要在对象创建之前完成赋值的过程. 二.值能不能改变的问题 ...
- final修饰的变量就是常量?final修饰局部变量在栈还是堆还是常量池中?
概念 常量池 常量池的好处 Class类文件中的常量池 常量池 运行时常量池 包装类常量池对象池 Java中装箱和拆箱 赋值时 方法调用时 方法运算时 参考 概念 什么是常量? 对于这个问题,可能很多 ...
- 被final修饰的变量到底能不能被修改
final:可以修饰类,方法,变量: 对类的修饰:表示类不可以被继承: 对方法修饰:表示该方法不能被子类重写: 对变量修饰:表示该变量不能被修改: 不知道大家有没有遇到一些很奇怪的现象,就是被fina ...
- Java中被final修饰的变量的几种赋值方式
关于final final 表示"最后的.最终的"含义,变量一旦赋值后,不能被重新赋值.被 final 修饰的实例变量必须显式指定初始值. final 修饰符通常和 static ...
- java 中final修饰的变量_java中final修饰符的使用方法
本文为大家分享了java中final修饰符的使用,供大家参考,具体内容如下 1.final修饰符的用法: final可以修饰变量,被final修饰的变量被赋初始值之后,不能对它重新赋值. final可 ...
- 被final修饰的变量在哪存储_final,static,this,super 关键字总结,一点课堂(多岸学院)...
final 关键字 final关键字主要用在三个地方:变量.方法.类. 对于一个final变量,如果是基本数据类型的变量,则其数值一旦在初始化之后便不能更改:如果是引用类型的变量,则在对其初始化之后便 ...
最新文章
- 【shell】创建长目录,目录存在则忽略,缺失则创建
- win7修改网络计算机名字,小编分析win7系统修改计算机名字的操作方法
- nodejs文件服务器断点续传,基于Nodejs的大文件上传之断点续传
- 华为鸿蒙系统手机销量,两个品牌助力华为新生,但最终会是谁拯救谁
- c汇编语言程序框架培训,[010][x86汇编语言]学习用户程序的编写(c08.asm)
- BGP——本地优先级选路+BGP路由水平分割机制(讲解+配置命令)
- 期货市场技术分析06_长期图表和商品指数
- SDL2源代码分析1:初始化(SDL_Init())
- 关于Navicat Premium 12注册机被windows病毒防护自动删除的问题解决
- 基于javaweb,springboot银行管理系统
- SLA 、SLO SLI
- (sn0wbreeze保基带升级,redsnow,absinthe越狱)常用越狱工具下载:redsnow,absinthe,tinyumbrella,sn0wbreeze
- PDF可以修改吗,如何在PDF上修改文字
- 一个字的伤感网名又是一个伤感的故事
- Terminal Emulator for Android(安卓终端模拟器)的使用
- 【15.罗马数字转整数】
- 【夜读】影响一生的五大定律内心强大的人,有这五种特质
- 请更换备份电池 pos机_免费邮寄低费率POS机安全吗?为什么那么多免费POS机?请看视频...
- 【算法】leetcode 974. 和可被 K 整除的子数组(前缀和思想)
- 构造函数被私有化就没办法直接new一个对象
热门文章
- 网络上长说的监听某个端口是什么意思
- 计算机加密系统损坏如何修复,[修复] BitLocker驱动器加密无法使用,因为关键BitLocker系统文件丢失或损坏 | MOS86...
- Oracle数据库中的instr函数的用法
- 常见波形的傅里叶级数展开式
- 熔断器熔断时间标准_正确认识熔断器的熔断时间
- Zookeeper--四字命令
- 2019华师在线计算机,华师计算机基础客观作业2019.pdf
- 警猫眼Arduino源码分享,把闲置手机变成安防监控摄像头!
- ARM内核全解析,从ARM7,ARM9到Cortex-A7,A8....Cortex-A53,A57,A72
- Vue-组件嵌套之——父组件向子组件传值