這是java的一條規(guī)則窑睁。那么為什么會(huì)有這條規(guī)則呢?要想弄懂這個(gè)問(wèn)題葵孤,就需要弄懂局部?jī)?nèi)部類(lèi)對(duì)象和局部變量的生命周期誰(shuí)更長(zhǎng)的問(wèn)題担钮。
首先,看一段代碼尤仍,以沒(méi)有將變量聲明為final的代碼作為例子箫津,代碼如下:
class Outer{
Object obj;
public void outerMethod() {
//局部變量
int x = 5;
//定義在方法中的內(nèi)部類(lèi)稱(chēng)為局部?jī)?nèi)部類(lèi)
class Inner{
public String toString() {
System.out.println(x);//訪問(wèn)了局部變量x
return null;
}
}
//創(chuàng)建內(nèi)部類(lèi)實(shí)例
Inner in = new Inner();
in.toString();
//將內(nèi)部類(lèi)實(shí)例的引用賦值給obj
obj = in;
}
}
public class HelloDemo {
public static void main(String[] argr) {
Outer out = new Outer();
out.outerMethod();
}
}
如上面的第7行代碼所示,變量x沒(méi)有被聲明為final宰啦,如果是這樣的話苏遥,當(dāng)執(zhí)行完第26行的outMethod()方法后,outMethod()方法將出棧赡模,出棧后outMethod()方法里面定義的所有變量(x 和 in)都死亡了田炭,(但是此時(shí)內(nèi)部類(lèi)的對(duì)象還活著,直到它不再被使用才會(huì)被回收漓柑,也就是說(shuō)此內(nèi)部類(lèi)對(duì)象的生命周期比局部變量的生命周期長(zhǎng))教硫,并且在變量 in 死亡之前叨吮,in 的值賦值給了成員變量obj(第19行代碼),這時(shí)obj 指向了內(nèi)部類(lèi)的對(duì)象瞬矩,如果此時(shí)在27行執(zhí)行一條代碼: out.obj.toString();
那么這條代碼將會(huì)訪問(wèn)到局部變量 x茶鉴,但是此時(shí) x 已經(jīng)死亡了,內(nèi)部類(lèi)對(duì)象已經(jīng)訪問(wèn)不到 x 了丧鸯,因此這是相互矛盾的蛤铜。所以上面的代碼實(shí)際上并不能編譯通過(guò)。(在jdk8.0能編譯通過(guò)丛肢,那是因?yàn)樗鼨z測(cè)到局部?jī)?nèi)部類(lèi)訪問(wèn)了 x围肥,會(huì)默認(rèn)給 x 的前面加上隱式的final,如果在第8行加上一句代碼:x = 4蜂怎;編譯器將會(huì)報(bào)錯(cuò)穆刻,因?yàn)閒inal不允許 x 的值改變)
如果局部變量 x 被聲明為final后(在第七行的int前加上final),x 就代表了一個(gè)常量杠步,那么第15行的代碼實(shí)際上就變成了 System.out.println(5);
氢伟,這時(shí)內(nèi)部類(lèi)相當(dāng)于訪問(wèn)了一個(gè)數(shù)字5。這是沒(méi)任何問(wèn)題的幽歼,因此局部?jī)?nèi)部類(lèi)訪問(wèn)它所在方法的局部變量時(shí)朵锣,要求該局部變量必須聲明為final。究其根本原因甸私,是局部?jī)?nèi)部類(lèi)對(duì)象的生命周期比局部變量的生命周期長(zhǎng)诚些。