隨筆-128  評(píng)論-55  文章-5  trackbacks-0
          內(nèi)部類有兩種情況:

          (1) 在類中定義一個(gè)類(私有內(nèi)部類,靜態(tài)內(nèi)部類)

          (2) 在方法中定義一個(gè)類(局部?jī)?nèi)部類,匿名內(nèi)部類)

          1、揭露類中內(nèi)部類

          ????? 我們首先看看類中內(nèi)部類的兩個(gè)特點(diǎn):

          ???? (1) 在外部類的作用范圍內(nèi)可以任意創(chuàng)建內(nèi)部類對(duì)象,即使內(nèi)部類是私有的(私有內(nèi)部類)。即內(nèi)部類對(duì)包圍它的外部類可見。

          //代碼2:內(nèi)部類對(duì)外部類可見 ??
          1. class?Outer{ ??
          2. ?????//創(chuàng)建私有內(nèi)部類對(duì)象 ??
          3. ?????public?Inner?in=new?Inner(); ??
          4. ?????//私有內(nèi)部類 ??
          5. ?????private?class?Inner{ ??
          6. ??????????... ??
          7. ?????} ??
          8. }???


          (2) 在內(nèi)部類中可以訪問(wèn)其外部類的所有域,即使是私有域。即外部類對(duì)內(nèi)部類可見。

          //代碼3:外部類對(duì)內(nèi)部類可見 ??
          1. class?Outer{ ??
          2. ???????//外部類私有數(shù)據(jù)域 ??
          3. ???????private?int?data=0; ??
          4. ???????//內(nèi)部類 ??
          5. ???????class?Inner{ ??
          6. ???????????void?print(){ ??
          7. ?????????????????//內(nèi)部類訪問(wèn)外部私有數(shù)據(jù)域 ??
          8. ?????????????????System.out.println(data); ??
          9. ???????????}? ??
          10. ???????} ??
          11. }??

          ?????? 問(wèn)題來(lái)了:上面兩個(gè)特點(diǎn)到底如何辦到的呢??jī)?nèi)部類的"內(nèi)部"到底發(fā)生了什么?

          ????? 其實(shí),內(nèi)部類是Java編譯器一手操辦的。虛擬機(jī)并不知道內(nèi)部類與常規(guī)類有什么不同。編譯器是如何瞞住虛擬機(jī)的呢?


          ???? 對(duì)內(nèi)部類進(jìn)行編譯后發(fā)現(xiàn)有兩個(gè)class文件:Outer.classOuter$Inner.class。這說(shuō)明內(nèi)部類Inner仍然被編譯成一個(gè)獨(dú)立的類(Outer$Inner.class),而不是Outer類的某一個(gè)域。虛擬機(jī)運(yùn)行的時(shí)候,也是把Inner作為一種常規(guī)類來(lái)處理的。

          ??????? 但問(wèn)題來(lái)了,即然是兩個(gè)常規(guī)類,為什么他們之間可以互相訪問(wèn)私有域那(最開始提到的兩個(gè)內(nèi)部類特點(diǎn))?這就要問(wèn)問(wèn)編譯器到底把這兩個(gè)類編譯成什么東西了。

          ??????? 我們利用reflect反射機(jī)制來(lái)探查了一下內(nèi)部類編譯后的情況(關(guān)于探查類內(nèi)部機(jī)制的代碼提供在下面的附件里Reflect.java)。

          ??????? (1)、編譯代碼2生成Outer$Inner.class 文件后使用ReflectUtil.reflect("Outer$Inner")對(duì)內(nèi)部類Inner進(jìn)行反射。運(yùn)行結(jié)果發(fā)現(xiàn)了三個(gè)隱含的成分:??????????

          class?Outer$Inner ??
          1. { ??
          2. ????????Outer$Inner(Outer,Outer$Inner);??//包可見構(gòu)造器 ??
          3. ????????private?Outer$Inner(Outer);???//私有構(gòu)造器將設(shè)置this$0域 ??
          4. ????????final?Outer?this$0;???//外部類實(shí)例域this$0 ??
          5. }??

          ????? 好了,現(xiàn)在我們可以解釋上面的第一個(gè)內(nèi)部類特點(diǎn)了:為什么外部類可以創(chuàng)建內(nèi)部類的對(duì)象?

          ???? 首先編譯器將外、內(nèi)部類編譯后放在同一個(gè)包中。

          ??????? 然后在內(nèi)部類中附加一個(gè)包可見構(gòu)造器。

          ??????? 這樣,虛擬機(jī)運(yùn)行Outer類中Inner in=new Inner();實(shí)際上調(diào)用的是包可見構(gòu)造: new Outer$Inner(this,null)。

          ??????? 因此即使是private內(nèi)部類,也會(huì)通過(guò)隱含的包可見構(gòu)造器成功的獲得私有內(nèi)部類的構(gòu)造權(quán)限。

          ???? (2)、編譯代碼3生成Outer.class文件,然后使用ReflectUtil.reflect("Outer")對(duì)外部類Outer進(jìn)行反射。 運(yùn)行結(jié)果發(fā)現(xiàn)一個(gè)隱含成分如下:

          ?
          1. class?Outer ??
          2. { ??
          3. ??????????static?int?access$0(Outer);??//靜態(tài)方法,返回值是外部類私有域?data?的值。 ??
          4. }??

          ????? 現(xiàn)在可以解釋第二個(gè)特點(diǎn)了:為什么內(nèi)部類可以引用外部類的私有域?

          ????????原因的關(guān)鍵就在編譯器在外圍類中添加了靜態(tài)方法access$0。 它將返回值作為參數(shù)傳遞給他的對(duì)象域data。這樣內(nèi)部類Inner中的打印語(yǔ)句:

          ???????????????????? System.out.println(data);

          ???????? 實(shí)際上運(yùn)行的時(shí)候調(diào)用的是:

          ???????????????? System.out.println(access$0(Outer));

          總結(jié)一下編譯器對(duì)類中內(nèi)部類做的手腳吧:

          (1)? 在內(nèi)部類中偷偷摸摸的創(chuàng)建了包可見構(gòu)造器,從而使外部類獲得了創(chuàng)建權(quán)限。

          (2)? 在外部類中偷偷摸摸的創(chuàng)建了訪問(wèn)私有變量的靜態(tài)方法,從而使內(nèi)部類獲得了訪問(wèn)權(quán)限。

          這樣,類中定義的內(nèi)部類無(wú)論私有,公有,靜態(tài)都可以被包圍它的外部類所訪問(wèn)。

          ?

          2、方法中內(nèi)部類的特點(diǎn)

          ????? 方法內(nèi)部類也有兩個(gè)特點(diǎn)

          ????? (1)? 方法中的內(nèi)部類沒(méi)有訪問(wèn)修飾符,即方法內(nèi)部類對(duì)包圍它的方法之外的任何東西都不可見。

          ????? (2)? 方法內(nèi)部類只能夠訪問(wèn)該方法中的局部變量,所以也叫局部?jī)?nèi)部類。而且這些局部變量一定要是final修飾的常量。

          class?Outter{ ??
          1. ??????public?void?outMethod(){ ??
          2. ?????????????final?int?beep=0; ??
          3. ?????????????class?Inner{ ??
          4. ???????????????????//使用beep ??
          5. ?????????????} ??
          6. ?????????????Inner?in=new?Inner(); ??
          7. ??????} ??
          8. }??

          ????? 這又是為什么呢?

          ????? (1) 我們首先對(duì)Outter類進(jìn)行反射發(fā)現(xiàn),Outter中再也沒(méi)有返回私有域的隱藏方法了。

          ????? (2) 對(duì)Inner類的反射發(fā)現(xiàn),Inner類內(nèi)部多了一個(gè)對(duì)beep變量的備份隱藏域:final int val$i;

          ????? 我們可以這樣解釋Inner類中的這個(gè)備份常量域,首先當(dāng)JVM運(yùn)行到需要?jiǎng)?chuàng)建Inner對(duì)象之后,Outter類已經(jīng)全部運(yùn)行完畢,這是垃圾回收機(jī)制很有可能釋放掉局部變量beep。那么Inner類到哪去找beep變量呢?

          ????? 編譯器又出來(lái)幫我們解決了這個(gè)問(wèn)題,他在Inner類中創(chuàng)建了一個(gè)beep的備份,也就是說(shuō)即使Ouuter中的beep被回收了,Inner中還有一個(gè)備份存在,自然就不怕找不到了。

          ????? 但是問(wèn)題又來(lái)了。如果Outter中的beep不停的在變化那。那豈不是也要讓備份的beep變量無(wú)時(shí)無(wú)刻的變化。為了保持局部變量與局部?jī)?nèi)部類中備份域保持一致。編譯器不得不規(guī)定死這些局部域必須是常量,一旦賦值不能再發(fā)生變化了。

          ????? 所以為什么局部?jī)?nèi)部類應(yīng)用外部方法的域必須是常量域的原因所在了。



          Author: orangelizq
          email: orangelizq@163.com

          歡迎大家訪問(wèn)我的個(gè)人網(wǎng)站 萌萌的IT人
          posted on 2010-04-21 15:00 桔子汁 閱讀(508) 評(píng)論(1)  編輯  收藏 所屬分類: J2SE

          評(píng)論:
          # re: [轉(zhuǎn)]領(lǐng)略內(nèi)部類的“內(nèi)部”[未登錄](méi) 2010-04-21 23:04 | zhrb
          所謂的包可見構(gòu)造器到底是個(gè)什么東西?  回復(fù)  更多評(píng)論
            
          主站蜘蛛池模板: 谢通门县| 沁水县| 岑巩县| 焦作市| 武乡县| 玛纳斯县| 武平县| 普定县| 邵东县| 西和县| 宁强县| 渝北区| 石城县| 巴里| 临西县| 海原县| 佛冈县| 正定县| 泸定县| 平乡县| 西峡县| 彩票| 神农架林区| 曲周县| 方城县| 锦屏县| 班玛县| 古交市| 图们市| 合作市| 黄大仙区| 长兴县| 虎林市| 东丰县| 廊坊市| 盐津县| 安化县| 呼玛县| 中西区| 自治县| 福建省|