被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修饰的变量相关推荐

  1. final修饰的变量是引用不能改变还是引用的对象不能改变

    我们都知道final修饰变量时 会变为常量,但是使 用final关键字修饰一个变量时,是引用不能变,还是引用的对象不能变? 下面让我们来看这段代码: [java] view plain copy /* ...

  2. final修饰的变量就是常量?

    概念 什么是常量? 对于这个问题,可能很多人都可以脱口而出 : 用final修饰的变量是常量 ,或者是在编译时期定义好的字符串.(字符串常量) 但是这种说法是不严谨的,因为准确来说 : 常量是用fin ...

  3. final修饰的变量必须初始化吗?

    final关键字的用法大家应该都知道. 修饰的类不能被继承. 修饰的方法子类可以使用,但是不能进行重写. 修饰的变量只能被赋值一次,引用不可变. 引用不可变的变量,只能被赋值一次.但是如果变量是对象, ...

  4. 关于final修饰的变量赋值的问题

    一.赋值的方式 1.可以定义变量时直接赋值 2.可以在代码块中进行赋值(静态代码块和构造代码块) 3.可以再构造方法中进行赋值. 总结起来,就是要在对象创建之前完成赋值的过程. 二.值能不能改变的问题 ...

  5. final修饰的变量就是常量?final修饰局部变量在栈还是堆还是常量池中?

    概念 常量池 常量池的好处 Class类文件中的常量池 常量池 运行时常量池 包装类常量池对象池 Java中装箱和拆箱 赋值时 方法调用时 方法运算时 参考 概念 什么是常量? 对于这个问题,可能很多 ...

  6. 被final修饰的变量到底能不能被修改

    final:可以修饰类,方法,变量: 对类的修饰:表示类不可以被继承: 对方法修饰:表示该方法不能被子类重写: 对变量修饰:表示该变量不能被修改: 不知道大家有没有遇到一些很奇怪的现象,就是被fina ...

  7. Java中被final修饰的变量的几种赋值方式

    关于final final 表示"最后的.最终的"含义,变量一旦赋值后,不能被重新赋值.被 final 修饰的实例变量必须显式指定初始值. final 修饰符通常和 static ...

  8. java 中final修饰的变量_java中final修饰符的使用方法

    本文为大家分享了java中final修饰符的使用,供大家参考,具体内容如下 1.final修饰符的用法: final可以修饰变量,被final修饰的变量被赋初始值之后,不能对它重新赋值. final可 ...

  9. 被final修饰的变量在哪存储_final,static,this,super 关键字总结,一点课堂(多岸学院)...

    final 关键字 final关键字主要用在三个地方:变量.方法.类. 对于一个final变量,如果是基本数据类型的变量,则其数值一旦在初始化之后便不能更改:如果是引用类型的变量,则在对其初始化之后便 ...

最新文章

  1. 【shell】创建长目录,目录存在则忽略,缺失则创建
  2. win7修改网络计算机名字,小编分析win7系统修改计算机名字的操作方法
  3. nodejs文件服务器断点续传,基于Nodejs的大文件上传之断点续传
  4. 华为鸿蒙系统手机销量,两个品牌助力华为新生,但最终会是谁拯救谁
  5. c汇编语言程序框架培训,[010][x86汇编语言]学习用户程序的编写(c08.asm)
  6. BGP——本地优先级选路+BGP路由水平分割机制(讲解+配置命令)
  7. 期货市场技术分析06_长期图表和商品指数
  8. SDL2源代码分析1:初始化(SDL_Init())
  9. 关于Navicat Premium 12注册机被windows病毒防护自动删除的问题解决
  10. 基于javaweb,springboot银行管理系统
  11. SLA 、SLO SLI
  12. (sn0wbreeze保基带升级,redsnow,absinthe越狱)常用越狱工具下载:redsnow,absinthe,tinyumbrella,sn0wbreeze
  13. PDF可以修改吗,如何在PDF上修改文字
  14. 一个字的伤感网名又是一个伤感的故事
  15. Terminal Emulator for Android(安卓终端模拟器)的使用
  16. 【15.罗马数字转整数】
  17. 【夜读】影响一生的五大定律内心强大的人,有这五种特质
  18. 请更换备份电池 pos机_免费邮寄低费率POS机安全吗?为什么那么多免费POS机?请看视频...
  19. 【算法】leetcode 974. 和可被 K 整除的子数组(前缀和思想)
  20. 构造函数被私有化就没办法直接new一个对象

热门文章

  1. 网络上长说的监听某个端口是什么意思
  2. 计算机加密系统损坏如何修复,[修复] BitLocker驱动器加密无法使用,因为关键BitLocker系统文件丢失或损坏 | MOS86...
  3. Oracle数据库中的instr函数的用法
  4. 常见波形的傅里叶级数展开式
  5. 熔断器熔断时间标准_正确认识熔断器的熔断时间
  6. Zookeeper--四字命令
  7. 2019华师在线计算机,华师计算机基础客观作业2019.pdf
  8. 警猫眼Arduino源码分享,把闲置手机变成安防监控摄像头!
  9. ARM内核全解析,从ARM7,ARM9到Cortex-A7,A8....Cortex-A53,A57,A72
  10. Vue-组件嵌套之——父组件向子组件传值