1. 程式人生 > >區域性內部類為什麼只能訪問final區域性變數,對於成員變數卻可以隨便訪問?

區域性內部類為什麼只能訪問final區域性變數,對於成員變數卻可以隨便訪問?

區域性內部類為什麼只能訪問final區域性變數,對於成員變數卻可以隨便訪問?

http://kingquake21.iteye.com/blog/1033436

部落格分類:  Java innerclass inner final 

區域性內部類為什麼只能訪問final區域性變數,對於成員變數卻可以隨便訪問?

Java程式碼   收藏程式碼
  1. public class OuterClass {  
  2.     private int memberField = 10;  
  3.       
  4.     public void outerDo(){  
  5.         final int localField = fromOther();  
  6.           
  7.         class InnerClass{  
  8.             public void innerDo(){  
  9.                 memberField = localField;  
  10.             }  
  11.         };  
  12.     }  
  13.   
  14.     private int fromOther() {  
  15.         return 20;  
  16.     }  
  17. }  
 

區域性變數和成員變數對於內部類而言,具有一定的共性,都是該內部類外面的變數。如果要求內部類只能訪問final的區域性變數是為了確保區域性變數不被修改的話,那麼內部類訪問成員變數應該也有類似的限制才對

 

 

我認為是由於他們的存活範圍導致了這個區別:

首先內部類的例項可以在方法結束後依然存活,區域性變數在方法結束後卻無法存活,所以在內部類中無法訪問NON-final的區域性變數;

而成員變數的存活時間是取決於外部類的例項的,內部類例項中都會引用當前外部類例項,所以他們擁有一致的生命週期,於是可以訪問成員變數。

 

剩下的問題是,為什麼可以訪問final的區域性變數呢?

如果將一個訪問了final的區域性變數的內部類進行反編譯,可以發現該變數是被作為建構函式的引數傳入進去的,與之一起傳入的引數還有外部類例項

......

com.study.innerclass.OuterClass$1InnerClass(com.study.innerclass.OuterClass, int);
  Code:
   Stack=2, Locals=3, Args_size=3
   0:    aload_0
   1:    aload_1
   2:    putfield    #12; //Field this$0:Lcom/study/innerclass/OuterClass;
   5:    aload_0
   6:    iload_2
   7:    putfield    #14; //Field val$localField:I
   10:    aload_0
   11:    invokespecial    #16; //Method java/lang/Object."<init>":()V
   14:    return
  LineNumberTable: 
   line 9: 0

  LocalVariableTable: 
   Start  Length  Slot  Name   Signature
   0      15      0    this       Lcom/study/innerclass/OuterClass$1InnerClass;

 

 

既然javac是這樣處理內部類的,那麼這與為內部類提供一個帶引數的建構函式就沒什麼兩樣了!

Java程式碼   收藏程式碼
  1. public class OuterClass {  
  2.     private int memberField = 10;  
  3.       
  4.     public void outerDo(){  
  5.         int localField = fromOther();  
  6.           
  7.         class InnerClass{  
  8.             private int local;  
  9.             public InnerClass(int local) {  
  10.                 this.local = local;  
  11.             }  
  12.             public void innerDo(){  
  13.                 memberField = this.local;  
  14.             }  
  15.         };  
  16.         new InnerClass(localField);  
  17.     }  
  18.   
  19.     private int fromOther() {  
  20.         return 20;  
  21.     }  
  22. }