內部類訪問局部變量時,為什么需要加final關鍵字


是變量的作用域的問題,因為匿名內部類是出現在一個方法的內部的,如果它要訪問這個方法的參數或者方法中定義的變量,則這些參數和變量必須被修飾為final。因為雖然匿名內部類在方法的內部,但實際編譯的時候,內部類編譯成Outer.Inner,這說明內部類所處的位置和外部類中的方法處在同一個等級上,外部類中的方法中的變量或參數只是方法的局部變量,這些變量或參數的作用域只在這個方法內部有效。因為編譯的時候內部類和方法在同一級別上,所以方法中的變量或參數只有為final,內部類才可以引用。

Java代碼: 
package com.cxz.j2se;   
  
public class MyClass {   
    public MyClass() {   
        final int finalValue = 10;   
        int not$Final = 20;   
        MyInterface myInterface = new MyInterface() {   
            public void functionWithoutPara() {   
                //compile Error   
                //System.out.println(noFinal);    
                System.out.println(finalValue);   
            }   
  
            public void functionWithPara(int num) {   
                System.out.println("The parameter " + num   
                        + " has been passed by the method");   
            }   
  
        };   
        myInterface.functionWithoutPara();   
        myInterface.functionWithPara(not$Final);   
        System.out.println(myInterface.getClass().getName());   
    }   
  
    public static void main(String[] args) {   
        new MyClass();   
  
    }   
  

二、為什么局部內部類只能訪問final變量
簡單的來說是作用域的問題。就好像方法外面做的事情並不能改變方法內才定義的變量,因為你並不知道方法里面這個時候已經存在了這個局部變量了沒有。在這個內部類中方法里面的本地變量是失效的,也就是不在作用域內,所以是不能夠訪問的

但是為什么這里用final卻又可以訪問呢? 
因為Java采用了一種copy   local   variable的方式來實現,也就是說把定義為final的局部變量拷貝過來用,而引用的也可以拿過來用,只是不能重新賦值。從而造成了可以access   local   variable的假象,而這個時候由於不能重新賦值,所以一般不會造成不可預料的事情發生

三、如果定義一個局部內部類,並且局部內部類使用了一個在其外部定義的對象,為什么編譯器會要求其參數引用是final呢?
注意:局部內部類,包括匿名內部類。

原因如下:

abstract class ABSClass{
public abstract void print();
}

public class Test2{
public static void test(final String s){//一旦參數在匿名類內部使用,則必須是final
ABSClass c=new ABSClass(){
public void print(){
System.out.println(s);
}
};
c.print();
}
public static void main(String[] args){
test("Hello World!");
}
}

JVM中每個進程都會有多個根,每個static變量,方法參數,局部變量,當然這都是指引用類型.基礎類型是不能作為根的,根其實就是一個存儲地址.垃圾回收器在工作時先從根開始遍歷它引用的對象並標記它們,如此遞歸到最末梢,所有根都遍歷后,沒有被標記到的對象說明沒有被引用,那么就是可以被回收的對象(有些對象有finalized方法,雖然沒有引用,但JVM中有一個專門的隊列引用它們直到finalized方法被執行后才從該隊列中移除成為真正沒有引用的對象,可以回收,這個與本主題討論的無關,包括代的划分等以后再說明).這看起來很好.

但是在內部類的回調方法中,s既不可能是靜態變量,也不是方法中的臨時變量,也不是方法參數,它不可能作為根,在內部類中也沒有變量引用它,它的根在內部類外部的那個方法中,如果這時外面變量s重指向其它對象,則回調方法中的這個對象s就失去了引用,可能被回收,而由於內部類回調方法大多數在其它線程中執行,可能還要在回收后還會繼續訪問它.這將是什么結果?

而使用final修飾符不僅會保持對象的引用不會改變,而且編譯器還會持續維護這個對象在回調方法中的生命周期.所以這才是final變量和final參數的根本意義.
文章出處:飛諾網(www.firnow.com):http://dev.firnow.com/course/3_program/java/javajs/20100719/460085.html

另詳解:http://blog.csdn.net/zzp_403184692/article/details/8014235


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM