Java中局部?jī)?nèi)部類可以訪問(wèn)它所在方法中定義的final修飾的局部變量的合理解釋
Posted on 2007-12-22 11:45 IceWee 閱讀(2153) 評(píng)論(1) 編輯 收藏 所屬分類: Java標(biāo)題有點(diǎn)長(zhǎng),可能有點(diǎn)語(yǔ)病,先別管那么多!
首先看下面的這段代碼:
public class LocalInnerClassTest{
public static void main(String[] args){
Outer obj=new Outer(); //生成一個(gè)外部類對(duì)象
SuperInner si=obj.outer(); //調(diào)用外部類中的outer()方法,返回一個(gè)SuperInner類型對(duì)象賦值給si
si.m1(); //調(diào)用被覆蓋的方法m1(),輸出:Inner's m1() 20
}
}

/**
*定義一個(gè)接口SuperInner,內(nèi)部定義一個(gè)抽象方法m1(),無(wú)返回類型
*/
interface SuperInner{
public void m1();
}

/**
*定義一個(gè)類Outer,內(nèi)部只定義一個(gè)方法outer(),返回類型為SuperInner
*/
class Outer{
public SuperInner outer(){
int a=10; //方法中定義一個(gè)局部變量a,并賦值為10
final int b=20; //再定義一個(gè)final局部變量b,初始化為20

class Inner implements SuperInner{ //在outer()方法中定義一個(gè)局部?jī)?nèi)部類Inner,實(shí)現(xiàn)接口SuperInner
public void m1(){ //類中只有一個(gè)覆蓋接口SuperInner的方法m1()
System.out.println("Inner's m1()"+a); //編譯報(bào)錯(cuò)
System.out.println("Inner's m1() "+b); //編譯通過(guò),輸出:Inner's m1() 20
}
}
return new Inner();
}
}


我們先從主方法開(kāi)始看代碼的執(zhí)行順序,先生成一個(gè)Outer類對(duì)象obj,obj調(diào)用本類中方法outer();程序開(kāi)始跳到outer()方法內(nèi)執(zhí)行程序語(yǔ)句,先后生成局部變量a和b,再定義一個(gè)局部?jī)?nèi)部類Inner,返回一個(gè)SuperInner類型的對(duì)象。將返回的SuperInner類型對(duì)象地址傳給SuperInner類型對(duì)象si。si再調(diào)用m1()方法,因?yàn)橐呀?jīng)在局部?jī)?nèi)部類中覆蓋了接口中的m1()方法,所以將調(diào)用局部?jī)?nèi)部類中的m1()方法,程序跳到局部?jī)?nèi)部類中m1()方法內(nèi)執(zhí)行程序語(yǔ)句,先輸出一段字符串和a,結(jié)果編譯報(bào)錯(cuò),先 將這條程序語(yǔ)句隱藏,執(zhí)行下面的語(yǔ)句,你會(huì)發(fā)現(xiàn)編譯通過(guò)而且輸出Inner's m1() 20!
為什么會(huì)這樣呢?大家都知道局部變量?jī)H僅在一個(gè)范圍內(nèi)有效,在方法調(diào)用完就被內(nèi)存釋放,在Outer類對(duì)象obj調(diào)用outer()方法時(shí),a和b才產(chǎn)生,調(diào)用結(jié)束后被內(nèi)存釋放,那么b這個(gè)值也就不復(fù)存在了,為什么還會(huì)輸出20呢?難道局部變量被final修飾就不會(huì)被內(nèi)存釋放而保留?
其實(shí)有部分操作對(duì)于程序員是透明的,那是JAVA語(yǔ)言開(kāi)發(fā)者的小把戲,在定義a和b 時(shí)JVM(JAVA虛擬機(jī))做了程序員看不到的操作,他將b拷貝了一份給局部?jī)?nèi)部類,也就是說(shuō)JVM在局部?jī)?nèi)部類中定義了一個(gè)final int b=20;這個(gè)操作程序員是不知道的!當(dāng)調(diào)用m1()方法時(shí)輸出的20并不是原來(lái)outer()方法中定義的b,而僅僅是JVM拷貝的一個(gè)副本。那么為什么a沒(méi)被打印出呢?那是因?yàn)镴VM并沒(méi)有拷貝它,因?yàn)闆](méi)有final修飾,說(shuō)明它可以被修改,如果把a(bǔ) 改為 a++,此時(shí)JVM就不知道拷貝a還是a++了,所以對(duì)于無(wú)final修飾的局部變量JVM是不會(huì)拷貝傳給局部?jī)?nèi)部類的,自然無(wú)法打輸出!
首先看下面的這段代碼:








/**






/**


















我們先從主方法開(kāi)始看代碼的執(zhí)行順序,先生成一個(gè)Outer類對(duì)象obj,obj調(diào)用本類中方法outer();程序開(kāi)始跳到outer()方法內(nèi)執(zhí)行程序語(yǔ)句,先后生成局部變量a和b,再定義一個(gè)局部?jī)?nèi)部類Inner,返回一個(gè)SuperInner類型的對(duì)象。將返回的SuperInner類型對(duì)象地址傳給SuperInner類型對(duì)象si。si再調(diào)用m1()方法,因?yàn)橐呀?jīng)在局部?jī)?nèi)部類中覆蓋了接口中的m1()方法,所以將調(diào)用局部?jī)?nèi)部類中的m1()方法,程序跳到局部?jī)?nèi)部類中m1()方法內(nèi)執(zhí)行程序語(yǔ)句,先輸出一段字符串和a,結(jié)果編譯報(bào)錯(cuò),先 將這條程序語(yǔ)句隱藏,執(zhí)行下面的語(yǔ)句,你會(huì)發(fā)現(xiàn)編譯通過(guò)而且輸出Inner's m1() 20!
為什么會(huì)這樣呢?大家都知道局部變量?jī)H僅在一個(gè)范圍內(nèi)有效,在方法調(diào)用完就被內(nèi)存釋放,在Outer類對(duì)象obj調(diào)用outer()方法時(shí),a和b才產(chǎn)生,調(diào)用結(jié)束后被內(nèi)存釋放,那么b這個(gè)值也就不復(fù)存在了,為什么還會(huì)輸出20呢?難道局部變量被final修飾就不會(huì)被內(nèi)存釋放而保留?
其實(shí)有部分操作對(duì)于程序員是透明的,那是JAVA語(yǔ)言開(kāi)發(fā)者的小把戲,在定義a和b 時(shí)JVM(JAVA虛擬機(jī))做了程序員看不到的操作,他將b拷貝了一份給局部?jī)?nèi)部類,也就是說(shuō)JVM在局部?jī)?nèi)部類中定義了一個(gè)final int b=20;這個(gè)操作程序員是不知道的!當(dāng)調(diào)用m1()方法時(shí)輸出的20并不是原來(lái)outer()方法中定義的b,而僅僅是JVM拷貝的一個(gè)副本。那么為什么a沒(méi)被打印出呢?那是因?yàn)镴VM并沒(méi)有拷貝它,因?yàn)闆](méi)有final修飾,說(shuō)明它可以被修改,如果把a(bǔ) 改為 a++,此時(shí)JVM就不知道拷貝a還是a++了,所以對(duì)于無(wú)final修飾的局部變量JVM是不會(huì)拷貝傳給局部?jī)?nèi)部類的,自然無(wú)法打輸出!