是變量的作用域的問(wèn)題,因?yàn)槟涿麅?nèi)部類(lèi)是出現(xiàn)在一個(gè)方法的內(nèi)部的,如果它要訪(fǎng)問(wèn)這個(gè)方法的參數(shù)或者方法中定義的變量,則這些參數(shù)和變量必須被修飾為final。因?yàn)殡m然匿名內(nèi)部類(lèi)在方法的內(nèi)部,但實(shí)際編譯的時(shí)候,內(nèi)部類(lèi)編譯成Outer.Inner,這說(shuō)明內(nèi)部類(lèi)所處的位置和外部類(lèi)中的方法處在同一個(gè)等級(jí)上,外部類(lèi)中的方法中的變量或參數(shù)只是方法的局部變量,這些變量或參數(shù)的作用域只在這個(gè)方法內(nèi)部有效。因?yàn)榫幾g的時(shí)候內(nèi)部類(lèi)和方法在同一級(jí)別上,所以方法中的變量或參數(shù)只有為final,內(nèi)部類(lèi)才可以引用。
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(); }}
二、為什么局部?jī)?nèi)部類(lèi)只能訪(fǎng)問(wèn)final變量 簡(jiǎn)單的來(lái)說(shuō)是作用域的問(wèn)題。就好像方法外面做的事情并不能改變方法內(nèi)才定義的變量,因?yàn)槟悴⒉恢婪椒ɡ锩孢@個(gè)時(shí)候已經(jīng)存在了這個(gè)局部變量了沒(méi)有。在這個(gè)內(nèi)部類(lèi)中方法里面的本地變量是失效的,也就是不在作用域內(nèi),所以是不能夠訪(fǎng)問(wèn)的
但是為什么這里用final卻又可以訪(fǎng)問(wèn)呢? 因?yàn)镴ava采用了一種copy local variable的方式來(lái)實(shí)現(xiàn),也就是說(shuō)把定義為final的局部變量拷貝過(guò)來(lái)用,而引用的也可以拿過(guò)來(lái)用,只是不能重新賦值。從而造成了可以access local variable的假象,而這個(gè)時(shí)候由于不能重新賦值,所以一般不會(huì)造成不可預(yù)料的事情發(fā)生
三、如果定義一個(gè)局部?jī)?nèi)部類(lèi),并且局部?jī)?nèi)部類(lèi)使用了一個(gè)在其外部定義的對(duì)象,為什么編譯器會(huì)要求其參數(shù)引用是final呢?注意:局部?jī)?nèi)部類(lèi),包括匿名內(nèi)部類(lèi)。
原因如下:
abstract class ABSClass{ public abstract void print();}
public class Test2{ public static void test(final String s){//一旦參數(shù)在匿名類(lèi)內(nèi)部使用,則必須是final ABSClass c=new ABSClass(){ public void print(){ System.out.println(s); } }; c.print(); } public static void main(String[] args){ test("Hello World!"); }}
JVM中每個(gè)進(jìn)程都會(huì)有多個(gè)根,每個(gè)static變量,方法參數(shù),局部變量,當(dāng)然這都是指引用類(lèi)型.基礎(chǔ)類(lèi)型是不能作為根的,根其實(shí)就是一個(gè)存儲(chǔ)地址.垃圾回收器在工作時(shí)先從根開(kāi)始遍歷它引用的對(duì)象并標(biāo)記它們,如此遞歸到最末梢,所有根都遍歷后,沒(méi)有被標(biāo)記到的對(duì)象說(shuō)明沒(méi)有被引用,那么就是可以被回收的對(duì)象(有些對(duì)象有finalized方法,雖然沒(méi)有引用,但JVM中有一個(gè)專(zhuān)門(mén)的隊(duì)列引用它們直到finalized方法被執(zhí)行后才從該隊(duì)列中移除成為真正沒(méi)有引用的對(duì)象,可以回收,這個(gè)與本主題討論的無(wú)關(guān),包括代的劃分等以后再說(shuō)明).這看起來(lái)很好.
但是在內(nèi)部類(lèi)的回調(diào)方法中,s既不可能是靜態(tài)變量,也不是方法中的臨時(shí)變量,也不是方法參數(shù),它不可能作為根,在內(nèi)部類(lèi)中也沒(méi)有變量引用它,它的根在內(nèi)部類(lèi)外部的那個(gè)方法中,如果這時(shí)外面變量s重指向其它對(duì)象,則回調(diào)方法中的這個(gè)對(duì)象s就失去了引用,可能被回收,而由于內(nèi)部類(lèi)回調(diào)方法大多數(shù)在其它線(xiàn)程中執(zhí)行,可能還要在回收后還會(huì)繼續(xù)訪(fǎng)問(wèn)它.這將是什么結(jié)果?
而使用final修飾符不僅會(huì)保持對(duì)象的引用不會(huì)改變,而且編譯器還會(huì)持續(xù)維護(hù)這個(gè)對(duì)象在回調(diào)方法中的生命周期.所以這才是final變量和final參數(shù)的根本意義.
文章出處:http://blog.csdn.net/onisland/article/details/5807637
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注