Java內(nèi)部類

[toc]

內(nèi)部類.png

內(nèi)部類

  • 內(nèi)部類作為外部類的成員,可以使用人已訪問控制符修飾。
  • 外部類的上一級程序單元是包栽惶,所以只有兩個作用域:同一個包內(nèi)、任意位置汁蝶。因此需要兩種權(quán)限:包訪問權(quán)限幔亥、公開訪問權(quán)限针肥,對應(yīng)省略訪問修飾控制符和public訪問控制符握恳。因此如果一個外部類不使用任何訪問控制符修飾,則只能被同一個包中其他類訪問拔稳。
  • 內(nèi)部類的上一程序單元是外部類礁遵,所以具有4個作用域:同一個類政勃、同一個包懒叛、父子類、和任意位置拆檬,可以有4種訪問權(quán)限控制逝钥。
  • 成員內(nèi)部類的class文件格式為:OuterClass$InnerClass.class
  • 外部類成員變量持际、內(nèi)部類成員變量與內(nèi)部類里方法的局部變量同名,則可以通過使用this、外部類類名.this作為限定區(qū)分展鸡。

非靜態(tài)內(nèi)部類

定義:一個類放在另一個類的內(nèi)部定義涡尘。

大部分時候都被作為成員內(nèi)部類定義座泳,而不是局部內(nèi)部類。
可以直接訪問外部類的private成員,反過來不成立

  • 因為在非靜態(tài)內(nèi)部類對象里啦扬,保存了一個它寄存的外部類對象的引用瞄摊。

  • 非靜態(tài)內(nèi)部類的方法內(nèi)訪問某個變量時:
    1.系統(tǒng)優(yōu)先在方法內(nèi)查找是否存在該名字的局部變量,如果存在即使用蹲嚣;
    2.到該方法所在的內(nèi)部類中查找是否存在改名字的成員變量,如果存在即使用狂丝;
    3.到內(nèi)部類所在的外部類中查找,如不存在出現(xiàn)編譯錯誤:提示找不到該變量。

  • 非靜態(tài)內(nèi)部類成員只有在非靜態(tài)內(nèi)部類范圍內(nèi)是可知的叛本,并不能被外部類直接使用营搅。如果外部類需要訪問非靜態(tài)內(nèi)部類成員峭拘,必須顯示創(chuàng)建非靜態(tài)內(nèi)部類對象來進行訪問。

  • 非靜態(tài)內(nèi)部類里不能有靜態(tài)方法姓惑、靜態(tài)Field唯沮、靜態(tài)初始化塊践险。


靜態(tài)內(nèi)部類

包括靜態(tài)成員、非靜態(tài)成員筷频。

  • 靜態(tài)成員不能訪問非靜態(tài)成員。
  • 靜態(tài)內(nèi)部類不能訪問外部類的實例成員惩猫,只能訪問外部類的類成員。
  • 靜態(tài)內(nèi)部類的實例方法也不能訪問外部類的實例成員左刽,只能訪問外部類的靜態(tài)成員。(靜態(tài)內(nèi)部類是外部類的類相關(guān)舅世,不是外部類的對象相關(guān)查辩。靜態(tài)內(nèi)部類對象不是寄存在外部類對象里的,而是寄存在外部類的類本身中。當靜態(tài)內(nèi)部類對象存在時,并不存在一個被他寄存的外部類壮莹,靜態(tài)內(nèi)部類對象里只有對外部類的類引用杂抽,沒有對外部類的對象應(yīng)用。)
  • 外部類不能直接訪問靜態(tài)內(nèi)部類成員刃唐,可以使用靜態(tài)內(nèi)部類的類名作為調(diào)用者來訪問靜態(tài)內(nèi)部類的類成員。
public class A{
    static class B{
        private static int pro1 = 5;
        private int pro2 = 9;
    }
    public void accessInnerB(){
        System.out.println(B.pro1);
            System.out.println(new B().pro2);
  
    }
}

內(nèi)部類的使用

(1)外部類內(nèi)部使用內(nèi)部類

不要再外部類的靜態(tài)成員中使用非靜態(tài)內(nèi)部類爽篷,靜態(tài)成員不能訪問非靜態(tài)成員袒啼。

(2)外部類以外使用非靜態(tài)內(nèi)部類

  • 內(nèi)部類不能使用private訪問控制權(quán)限,private修飾的內(nèi)部類只能在外部類的內(nèi)部使用按声。
  • 省略訪問控制符的內(nèi)部類钠惩,只能被與外部類處于同一個包中的其他類所訪問鲤遥。
  • 使用protected修飾的內(nèi)部類爹凹,可悲與外部類處于同一個包中的其他類和外部類的子類所訪問指郁。
  • 使用public修飾的內(nèi)部類拷呆,可以在任何地方被訪問绣溜。

(3)在外部類以外使用靜態(tài)內(nèi)部類

語法:new OuterClass.InnerConstructor()


局部內(nèi)部類

定義:把一個內(nèi)部類放在方法中定義

  • 上一級程序單元都為方法岁诉,不是類候生,所以目溉,所有的局部成員都不能使用static修飾。
  • 局部成員的作用域?qū)嵲谒诘姆椒ǎ渌绦騿卧肋h也不可能訪問另一個方法中的局部成員宽涌,所以所有局部成員都不能使用訪問控制符修飾平夜。

生成的class文件命名格式為:
OuterClass$NInnerClass.class.

public class LocalInnerClass
{
    public static void main(String[] args)
    {
        // 定義局部內(nèi)部類
        class InnerBase
        {
            int a;
        }
        // 定義局部內(nèi)部類的子類
        class InnerSub extends InnerBase
        {
            int b;
        }
        // 創(chuàng)建局部內(nèi)部類的對象
        InnerSub is = new InnerSub();
        is.a = 5;
        is.b = 8;
        System.out.println("InnerSub對象的a和b實例變量是:"
            + is.a + "," + is.b);
    }
}

匿名內(nèi)部類

定義:只需要使用一次的類,必須繼承一個父類

內(nèi)部不能是抽象類

系統(tǒng)在創(chuàng)建匿名內(nèi)部類時卸亮,會創(chuàng)建匿名內(nèi)部類的對象褥芒,因此,不允許將匿名內(nèi)部類定義成抽象類嫡良。

不能定義構(gòu)造器

  • 匿名內(nèi)部類沒有類名,無法定義構(gòu)造器献酗,但匿名內(nèi)部類可以定義實例初始化塊寝受,利用實例初始化塊來完成構(gòu)造器需要完成的事情。

  • 通過接口創(chuàng)建匿名內(nèi)部類時罕偎,也不能顯示創(chuàng)建構(gòu)造函數(shù)很澄,因此只有一個隱式的無參數(shù)構(gòu)造器,所以new接口名后的括號不能傳入?yún)?shù)值。

  • 通過繼承父類創(chuàng)建匿名內(nèi)部類時甩苛,將擁有和父類相似的構(gòu)造器蹂楣,既擁有相同形參列表。

  • 如果匿名內(nèi)部類需要訪問外部類的局部變量讯蒲,必須用final修飾符來修飾外部類的局部變量痊土。

  • 通過接口創(chuàng)建匿名內(nèi)部類
interface Product
{
    public double getPrice();
    public String getName();
}
public class AnonymousTest
{
    public void test(Product p)
    {
        System.out.println("購買了一個" + p.getName()
            + ",花掉了" + p.getPrice());
    }
    public static void main(String[] args)
    {
        AnonymousTest ta = new AnonymousTest();
        // 調(diào)用test()方法時墨林,需要傳入一個Product參數(shù)赁酝,
        // 此處傳入其匿名實現(xiàn)類的實例
        ta.test(new Product()
        {
            public double getPrice()
            {
                return 567.8;
            }
            public String getName()
            {
                return "AGP顯卡";
            }
        });
    }
}
  • 繼承父類創(chuàng)建匿名內(nèi)部類
abstract class Device
{
    private String name;
    public abstract double getPrice();
    public Device(){}
    public Device(String name)
    {
        this.name = name;
    }
    // 此處省略了name的setter和getter方法
    public void setName(String name)
    {
        this.name = name;
    }
    public String getName()
    {
        return this.name;
    }
}
public class AnonymousInner
{
    public void test(Device d)
    {
        System.out.println("購買了一個" + d.getName()
            + ",花掉了" + d.getPrice());
    }
    public static void main(String[] args)
    {
        AnonymousInner ai = new AnonymousInner();
        // 調(diào)用有參數(shù)的構(gòu)造器創(chuàng)建Device匿名實現(xiàn)類的對象
        ai.test(new Device("電子示波器")
        {
            public double getPrice()
            {
                return 67.8;
            }
        });
        // 調(diào)用無參數(shù)的構(gòu)造器創(chuàng)建Device匿名實現(xiàn)類的對象
        Device d = new Device()
        {
            // 初始化塊
            {
                System.out.println("匿名內(nèi)部類的初始化塊...");
            }
            // 實現(xiàn)抽象方法
            public double getPrice()
            {
                return 56.2;
            }
            // 重寫父類的實例方法
            public String getName()
            {
                return "鍵盤";
            }
        };
        ai.test(d);
    }
}

閉包 & 回調(diào)

閉包:能被調(diào)用的對象旭等,保存了它的作用域信息酌呆。
回調(diào):某個方法一旦獲得了內(nèi)部類對象的引用后,就可以再合適的時候反過來去調(diào)用外部類實例的方法搔耕。(允許客戶類通過內(nèi)部類引用來調(diào)用其外部類的方法)

  • 接口
interface Teachable
{
    void work();
}
  • 程序員
public class Programmer
{
    private String name;
    //Programmer類的兩個構(gòu)造器
    public Programmer(){}
    public Programmer(String name)
    {
        this.name = name;
    }
    //此處省略了name的setter和getter方法
    public void setName(String name)
    {
        this.name = name;
    }
    public String getName()
    {
        return this.name;
    }
    public void work()
    {
        System.out.println(name + "在燈下認真敲鍵盤...");
    }
}
public class TeachableProgrammer extends Programmer
{
    public TeachableProgrammer(){}
    public TeachableProgrammer(String name)
    {
        super(name);
    }
    //教學(xué)工作依然由TeachableProgrammer類定義
    private void teach()
    {
        System.out.println(getName() + "教師在講臺上講解...");
    }
    private class Closure implements Teachable
    {
        /*
        非靜態(tài)內(nèi)部類回調(diào)外部類實現(xiàn)work方法隙袁,非靜態(tài)內(nèi)部類引用的作用僅僅是
        向客戶類提供一個回調(diào)外部類的途徑
        */
        public void work()
        {
            teach();
        }
    }
    //返回一個非靜態(tài)內(nèi)部類引用,允許外部類通過該非靜態(tài)內(nèi)部類引用來回調(diào)外部類的方法
    public Teachable getCallbackReference()
    {
        return new Closure();
    }
}
public class TeachableProgrammerTest
{
    public static void main(String[] args)
    {
        TeachableProgrammer tp = new TeachableProgrammer("李剛");
        //直接調(diào)用TeachableProgrammer類從Programmer類繼承到的work方法
        tp.work();
        //表面上調(diào)用的是Closure的work方法弃榨,
        //實際上是回調(diào)TeachableProgrammer的teach方法
        tp.getCallbackReference().work();
    }
}


——整理自瘋狂Java

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末菩收,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子惭墓,更是在濱河造成了極大的恐慌坛梁,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,865評論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件腊凶,死亡現(xiàn)場離奇詭異划咐,居然都是意外死亡,警方通過查閱死者的電腦和手機钧萍,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,296評論 3 399
  • 文/潘曉璐 我一進店門褐缠,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人风瘦,你說我怎么就攤上這事队魏。” “怎么了万搔?”我有些...
    開封第一講書人閱讀 169,631評論 0 364
  • 文/不壞的土叔 我叫張陵胡桨,是天一觀的道長。 經(jīng)常有香客問我瞬雹,道長昧谊,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,199評論 1 300
  • 正文 為了忘掉前任酗捌,我火速辦了婚禮呢诬,結(jié)果婚禮上涌哲,老公的妹妹穿的比我還像新娘。我一直安慰自己尚镰,他們只是感情好阀圾,可當我...
    茶點故事閱讀 69,196評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著狗唉,像睡著了一般初烘。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上敞曹,一...
    開封第一講書人閱讀 52,793評論 1 314
  • 那天账月,我揣著相機與錄音,去河邊找鬼澳迫。 笑死局齿,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的橄登。 我是一名探鬼主播抓歼,決...
    沈念sama閱讀 41,221評論 3 423
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼拢锹!你這毒婦竟也來了谣妻?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,174評論 0 277
  • 序言:老撾萬榮一對情侶失蹤卒稳,失蹤者是張志新(化名)和其女友劉穎蹋半,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體充坑,經(jīng)...
    沈念sama閱讀 46,699評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡减江,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,770評論 3 343
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了捻爷。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片辈灼。...
    茶點故事閱讀 40,918評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖也榄,靈堂內(nèi)的尸體忽然破棺而出巡莹,到底是詐尸還是另有隱情,我是刑警寧澤甜紫,帶...
    沈念sama閱讀 36,573評論 5 351
  • 正文 年R本政府宣布降宅,位于F島的核電站,受9級特大地震影響囚霸,放射性物質(zhì)發(fā)生泄漏钉鸯。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,255評論 3 336
  • 文/蒙蒙 一邮辽、第九天 我趴在偏房一處隱蔽的房頂上張望唠雕。 院中可真熱鬧,春花似錦吨述、人聲如沸岩睁。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,749評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽捕儒。三九已至,卻和暖如春邓夕,著一層夾襖步出監(jiān)牢的瞬間刘莹,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,862評論 1 274
  • 我被黑心中介騙來泰國打工焚刚, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留点弯,地道東北人。 一個月前我還...
    沈念sama閱讀 49,364評論 3 379
  • 正文 我出身青樓矿咕,卻偏偏與公主長得像抢肛,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子碳柱,可洞房花燭夜當晚...
    茶點故事閱讀 45,926評論 2 361

推薦閱讀更多精彩內(nèi)容