final 语义

我们都知道final修饰的成员是不可变。下面分析final在内部类的语义特征。

首先看一个简单的例子。

 1 public class FinalExample {
 2 
 3 
 4     private String fis = "final-init";
 5 
 6     public void method1() {
 7 
 8         final String key = "key1";
 9 
10         new Thread(new Runnable() {
11             @Override
12             public void run() {
13                 System.out.println(key);
14                 System.out.println(fis);
15             }
16         });
17 
18     }
19 
20     public void method2() {
21         final String key = new String("key1");
22 
23         new Thread(new Runnable() {
24             @Override
25             public void run() {
26                 System.out.println(key);
27                 System.out.println(fis);
28             }
29         });
30     }
31 
32     public void method3(final String key) {
33 
34         new Thread(new Runnable() {
35             @Override
36             public void run() {
37                 System.out.println(key);
38                 System.out.println(fis);
39             }
40         });
41     }
42 
43 }
View Code

编译器生成的代码:

FinalExample类:

 1 public class FinalExample {
 2     private String fis = "final-init";
 3 
 4     public FinalExample() {
 5     }
 6 
 7     public void method1() {
 8         String key = "key1";
 9         new Thread(new Runnable() {
10             public void run() {
11                 System.out.println("key1");
12                 System.out.println(FinalExample.this.fis);
13             }
14         });
15     }
16 
17     public void method2() {
18         final String key = new String("key1");
19         new Thread(new Runnable() {
20             public void run() {
21                 System.out.println(key);
22                 System.out.println(FinalExample.this.fis);
23             }
24         });
25     }
26 
27     public void method3(final String key) {
28         new Thread(new Runnable() {
29             public void run() {
30                 System.out.println(key);
31                 System.out.println(FinalExample.this.fis);
32             }
33         });
34     }
35 }
View Code

方法1的内部类:

 1 class FinalExample$1 implements Runnable {
 2     FinalExample$1(FinalExample var1) {
 3         this.this$0 = var1;
 4     }
 5 
 6     public void run() {
 7         System.out.println("key1");
 8         System.out.println(FinalExample.access$000(this.this$0));
 9     }
10 }
View Code

方法2的内部类:

 1 class FinalExample$2 implements Runnable {
 2     FinalExample$2(FinalExample var1, String var2) {
 3         this.this$0 = var1;
 4         this.val$key = var2;
 5     }
 6 
 7     public void run() {
 8         System.out.println(this.val$key);
 9         System.out.println(FinalExample.access$000(this.this$0));
10     }
11 }
View Code

方法3的内部类:

 1 class FinalExample$3 implements Runnable {
 2     FinalExample$3(FinalExample var1, String var2) {
 3         this.this$0 = var1;
 4         this.val$key = var2;
 5     }
 6 
 7     public void run() {
 8         System.out.println(this.val$key);
 9         System.out.println(FinalExample.access$000(this.this$0));
10     }
11 }
View Code

以上可以看出,final修饰的局部变量。如果是引用类型的变量,内部类会生成一个有参构造方法,将此变量传入构造函数。然后通过外部类中的access$*()方法获取到外部类中的值(该方法是通过编译器生成的)。 如果是基本类型,值直接编译到class文件。

通过汇编指令,反编译暂未发现网上说的final内存屏障语义。

猜你喜欢

转载自www.cnblogs.com/hf-china/p/9578690.html