Java·final关键字用法详解

2019-03-26  本文已影响0人  Sarahhhh

1.修饰类

final class Test {}

2.修饰方法

public final void func() {}

3.修饰变量

final int i = 0;  //基本数据类型
final Object obj = new Object();  //引用类型

//允许'空白final'
final int x; 
final Object y;    

final成员变量

final参数

在方法范围内,final参数的值或者指向对象无法被修改。这一特性主要用来向匿名内部类传递数据,匿名类中所有变量都必须是final变量

编译时常量

以下几种情况的定义会被当作编译时常量,即在编译期间能知道它的确切值(通常在定义时就被初始化),并在编译时直接将其替换成字面值

static final int VALUE = 1;   // static + final
final int a = 1+2;  // final变量是基本数据类型或String类型,且在编译时能知道确切值
final String b = "hello"; 

举个例子

        String a = "hello2";
        final String b = "hello"; //b被当成了编译时常量,遇到b会替换成"Hello"
        String c = "hello";
        String d = b + 2; //对编译器而言,这句和 String d = "hello"+2; 是一样的
        String e = c + 2;
        System.out.println((a == d));    //输出True
        System.out.println((a == e));    //输出False

反编译字节码
编译后使用反编译工具javap,在命令行输入javap -v <类名>.class。其实不一定要用-v-c也可以的,只是展示的信息量不同,更多用法见javap -help

Constant pool:
   #1 = Methodref          #18.#45        // java/lang/Object."<init>":()V
   #2 = String             #46            // hello2
   #3 = String             #47            // hello
   #4 = InvokeDynamic      #0:#51         // #0:makeConcatWithConstants:(Ljava/lang/String;)Ljava/lang/String;
   #5 = Fieldref           #52.#53        // java/lang/System.out:Ljava/io/PrintStream;
   #6 = Methodref          #38.#54        // java/io/PrintStream.println:(Z)V
  #38 = Class              #68            // java/io/PrintStream
  #51 = NameAndType        #71:#72        // makeConcatWithConstants:(Ljava/lang/String;)Ljava/lang/String;
  #52 = Class              #73            // java/lang/System
  #53 = NameAndType        #74:#75        // out:Ljava/io/PrintStream;

-------------------------------------------------------------------------------
Code:
         0: ldc           #2                  // String hello2 
         2: astore_1                          // 存储变量a
         3: ldc           #3                  // String hello
         5: astore_2                          // 存储变量b
         6: ldc           #3                  // String hello
         8: astore_3                          // 存储变量c
         9: ldc           #2                  // String hello2
        11: astore        4                   // 存储变量d
        13: aload_3
        14: invokedynamic #4,  0              // InvokeDynamic #0:makeConcatWithConstants:(Ljava/lang/String;)Ljava/lang/String;
        19: astore        5                   // 存储变量e

// ldc:(入栈)常量值从常量池中推送至栈顶
// astore:(出栈)将栈顶引用型数值存入指定本地变量
// astore_1 等同于 astore 1,astore 4 等同于 astore_4,此处不必纠结
// invokedynamic:(调用方法)表明调用点要实际执行哪个方法

从例子中可以看到,d的值是定义时直接以字面值确定的(没有访问b),就像a、b、c一样,而e的值是先访问了c的值、再进行字符串连接才得到的

参考链接:http://www.51gjie.com/java/71.html

上一篇 下一篇

猜你喜欢

热点阅读