1. 程式人生 > >內部類訪問區域性變數的時候,為什麼變數必須加上final修飾

內部類訪問區域性變數的時候,為什麼變數必須加上final修飾

這裡的區域性變數就是在類方法中的變數,能訪問方法中變數的類當然也是區域性內部類了。 我們都知道,區域性變數在所處的函式執行完之後就釋放了,但是內部類物件如果還有引用指向的話它是還存在的。例如下面的程式碼:

class Outer{                                                                       
        public static void main(String[] args){
                Outer out = new Outer();
                Object obj = out.method();
        }   

        Object method(){
                int locvar = 1;
                class Inner{
                        void displayLocvar(){
                                System.out.println("locvar = " + locvar);
                        }
                }
                Object in = new Inner();
                return in; 
        }
}

當out.method()方法執行結束後,區域性變數 locvar 就消失了,但是在method()方法中 obj in = new Inner() 產生的 in 物件還存在引用obj,這樣物件就訪問了一個不存在的變數,是不允許的。這種矛盾是由區域性內部類可以訪問區域性變數但是區域性內部類物件和區域性變數的生命週期不同而引起的。

區域性內部類訪問區域性變數的機制

在java中,類是封裝的,內部類也不例外。我們知道,非靜態內部類能夠訪問外部類成員是因為它持有外部類物件的引用 Outer.this, 就像子類對像能夠訪問父類成員是持有父類物件引用super一樣。區域性內部類也和一般內部類一樣,只持有了Outer.this,能夠訪問外部類成員,但是它又是如何訪問到區域性變數的呢?

實際上java是將區域性變數作為引數傳給了局部內部類的建構函式,而將其作為內部類的成員屬性封裝在了類中。我們看到的內部類訪問區域性變數實際上只是訪問了自己的成員屬性而已,這和類的封裝性是一致的。那麼上面的程式碼實際上是這樣:

Object method(){
                int locvar = 1;
                class Inner{
                    private int obj;
                    public Inner(int obj){
                        this.obj = obj;
                    }
                        void displayLocvar(){
                                System.out.println("locvar = " + locvar);
                        }
                }
                Object in = new Inner(locvar);  //將locvar作為引數傳給構造,以初始話成員
                return in; 
        }

那麼問題又來了,我們寫程式碼的目的是在內部類中直接控制區域性變數和引用,但是java這麼整我們就不高興了,我在內部類中整半天想著是在操作外部變數,結果你給整個副本給我,我搞半天丫是整我自己的東西啊?要是java不這麼整吧,由破壞了封裝性--------你個區域性內部類牛啊,啥都沒有還能看區域性變數呢。這不是java風格,肯定不能這麼幹。這咋整呢? 想想,類的封裝性咱們一定是要遵守的,不能破壞大局啊。但又要保證兩個東西是一模一樣的,包括物件和普通變數,那就使用final嘛,當傳遞普通變數的之前我把它變成一個常量給你,當傳遞引用物件的時候加上final就聲明瞭這個引用就只能指著這一個物件了。這樣就保證了內外統一。