新聞中心
內(nèi)部類(lèi):在其它類(lèi)內(nèi)定義的類(lèi),不同于組合。雖然看上去象某種代碼隱藏機(jī)制,但可以實(shí)現(xiàn)更多功能 -了解包含它的類(lèi)并可與之交換數(shù)據(jù),而且內(nèi)部類(lèi)的代碼可以更優(yōu)雅、清晰。

成都網(wǎng)絡(luò)公司-成都網(wǎng)站建設(shè)公司創(chuàng)新互聯(lián)十年經(jīng)驗(yàn)成就非凡,專(zhuān)業(yè)從事網(wǎng)站建設(shè)、網(wǎng)站制作,成都網(wǎng)頁(yè)設(shè)計(jì),成都網(wǎng)頁(yè)制作,軟文營(yíng)銷(xiāo),廣告投放等。十年來(lái)已成功提供全面的成都網(wǎng)站建設(shè)方案,打造行業(yè)特色的成都網(wǎng)站建設(shè)案例,建站熱線:18980820575,我們期待您的來(lái)電!
內(nèi)部類(lèi)定義:包含在其它類(lèi)內(nèi)。使用與非內(nèi)部類(lèi)沒(méi)有太大區(qū)別。
典型用法:outer class通過(guò)方法返回inner class的引用。
區(qū)別之一:內(nèi)部類(lèi)名嵌套在外部類(lèi)(outer class)內(nèi),在Out class的non-static方法之外用OuterClassName.InnerClassName的形式定義內(nèi)部類(lèi)對(duì)象。
注意,非static內(nèi)部類(lèi)只能在Out class的non-static方法中生成對(duì)象;在其它類(lèi)中,也必須使用Out class的外部類(lèi)對(duì)象實(shí)例。這就保證了下面所說(shuō)的鏈接問(wèn)題。
區(qū)別之二:內(nèi)部類(lèi)可以為private和protected。
Inner Class只是一種名稱(chēng)隱藏(name-hiding)和組織代碼方式?NO。
內(nèi)部類(lèi)對(duì)象有一個(gè)到創(chuàng)建它的外部類(lèi)對(duì)象的鏈接(link to the enclosing object that made it),因而可以直接的、沒(méi)有任何限制地訪問(wèn)該外部類(lèi)對(duì)象的成員,而且內(nèi)部類(lèi)可以訪問(wèn)outer class的所有成員(包括private)(C++的嵌套類(lèi)沒(méi)有這個(gè)特性);而outer class訪問(wèn)inner class的成員,必須創(chuàng)建Inner class的對(duì)象,可以訪問(wèn)任何成員(包括private)。
內(nèi)部類(lèi)對(duì)象中隱式包含了一個(gè)外部類(lèi)對(duì)象的引用。內(nèi)部類(lèi)對(duì)象構(gòu)建需要outer class對(duì)象的引用,如果沒(méi)有,編譯報(bào)錯(cuò)(非靜態(tài)inner class)。
.this和.new:前者用來(lái)返回Outer class引用,編譯期可知道和檢查正確類(lèi)型,無(wú)運(yùn)行時(shí)開(kāi)銷(xiāo);后者用來(lái)由outer class對(duì)象創(chuàng)建其內(nèi)部類(lèi)的對(duì)象,OutClassObject.new InnerClassName ()(注意,不能用outClassObj.new OutClassName.InnerClassName())。
嵌套類(lèi)(nested class):static inner class,其對(duì)象創(chuàng)建不需要outer class對(duì)象引用,也可在static方法中創(chuàng)建。
內(nèi)部類(lèi)與upcasting
類(lèi)實(shí)現(xiàn)了接口(interface),其它方法就可以用該interface作為參數(shù),而不一定必須用該類(lèi)(包括類(lèi)對(duì)象定義)(類(lèi)似繼承)。可以利用upcasting->interface。
upcasting內(nèi)部類(lèi)->基類(lèi)或者接口(尤其是后者),使內(nèi)部類(lèi)有了用武之地。實(shí)現(xiàn)接口內(nèi)部類(lèi)可以完全不可見(jiàn)、不可用(通過(guò)private或protected),所獲得的只是基類(lèi)或接口的引用(通過(guò)private,無(wú)法進(jìn)行downcasting,protected,同一個(gè)包內(nèi),或者繼承類(lèi)可以進(jìn)行downcasting),方便隱藏實(shí)現(xiàn)細(xì)節(jié)。
接口成員自動(dòng)為public
private內(nèi)部類(lèi)可以阻止任何依賴(lài)于類(lèi)型的代碼,進(jìn)行所有實(shí)現(xiàn)細(xì)節(jié)的隱藏。而且,擴(kuò)展接口也沒(méi)有任何意義,因?yàn)闊o(wú)法訪問(wèn)pubic接口之外的方法,這可以使JAVA產(chǎn)生更有效率的代碼 。
inner class可以在任意作用域內(nèi)定義(如方法內(nèi))。
兩個(gè)理由:1. 實(shí)現(xiàn)一個(gè)接口
2. 需要一個(gè)不公開(kāi)的類(lèi)輔助解決復(fù)雜的問(wèn)題
inner class形式
1. 方法內(nèi)的內(nèi)部類(lèi); 2. 方法中的一個(gè)作用域內(nèi)的內(nèi)部類(lèi); 3. 實(shí)現(xiàn)接口的匿名內(nèi)部類(lèi); 4. 繼承的匿名內(nèi)部類(lèi)(基類(lèi)含有參的構(gòu)造器); 4. 進(jìn)行成員初始化的匿名內(nèi)部類(lèi); 5. 使用實(shí)例初始化塊進(jìn)行構(gòu)造的匿名內(nèi)部類(lèi)(匿名類(lèi)沒(méi)有構(gòu)造器)。
局部?jī)?nèi)部類(lèi)(local inner class) :在方法內(nèi)或方法的一個(gè)作用域中定義的內(nèi)部類(lèi)。局部?jī)?nèi)部類(lèi)在域外不可見(jiàn)并不代表其對(duì)象也不可用。條件域內(nèi)定義的內(nèi)部類(lèi)不代表它是條件創(chuàng)建的。
匿名內(nèi)部類(lèi)(anonymous inner class) :new T(){...}; {...}為匿名內(nèi)部類(lèi)的定義,";"不可少(;只是該語(yǔ)句的結(jié)束,而不是用來(lái)表示匿名內(nèi)部類(lèi)的結(jié)束,所以沒(méi)有什么特殊的地方),創(chuàng)建一個(gè)繼承自T的匿名類(lèi)的對(duì)象,得到的引用可自動(dòng)upcast to T。是前面定義內(nèi)部類(lèi)的一種簡(jiǎn)寫(xiě),只是該類(lèi)沒(méi)有名稱(chēng)。
前面是基類(lèi)構(gòu)造器為默認(rèn)構(gòu)造器的情況,當(dāng)基類(lèi)構(gòu)造器有參數(shù)時(shí):new T(args){...};此時(shí)會(huì)調(diào)用基類(lèi)相應(yīng)構(gòu)造器。
匿名內(nèi)部類(lèi)初始化 :當(dāng)需要用到外部定義類(lèi)的對(duì)象時(shí),傳遞的引用參數(shù)必須為final,否則編譯報(bào)錯(cuò);匿名類(lèi)不能有命名的構(gòu)造器(當(dāng)然不能,類(lèi)本身就沒(méi)有名字),可以通過(guò)實(shí)例初始化(instance initialization)來(lái)完成構(gòu)造器的功能。由于實(shí)例初始化不能重載(不代表只能有一個(gè)Instance initialization clause),所以匿名內(nèi)部類(lèi)只能有一個(gè)構(gòu)造器。
匿名內(nèi)部類(lèi)只能在繼承類(lèi)和實(shí)現(xiàn)接口中2選一,且只能實(shí)現(xiàn)一個(gè)接口。
prefer classes to interfaces. (寧愿選擇類(lèi),而不是接口?)
嵌套類(lèi)(nested class):static inner class。有點(diǎn)類(lèi)似C++嵌套類(lèi)的概念,但Java的嵌套類(lèi)可以訪問(wèn)outer class的所有成員(包括private,當(dāng)然只能通過(guò)外部類(lèi)對(duì)象訪問(wèn)non-static成員)。
1. 不需要通過(guò)outer class對(duì)象來(lái)創(chuàng)建嵌套類(lèi)對(duì)象(.new不可用?);
2. 不能通過(guò)嵌套類(lèi)對(duì)象訪問(wèn)non-static outer class對(duì)象(意思是像非嵌套類(lèi)那樣直接訪問(wèn));
3. 嵌套類(lèi)對(duì)象中不包含outer class對(duì)象引用(.this不可用)。
4. 非嵌套內(nèi)部類(lèi)不能有static成員、方法和嵌套類(lèi)(fields、methods級(jí)別必須與class本身一致,non-static不能含有static,non-static、static內(nèi)可以含有non-static)。
嵌套類(lèi)可以位于接口內(nèi)部,不違反接口的規(guī)則(不能定義接口實(shí)例?),只代表把嵌套類(lèi)位于接口的命名空間下,位于接口內(nèi)部的類(lèi)自動(dòng)為public static(public嵌套類(lèi)),而且嵌套類(lèi)本身就可以實(shí)現(xiàn)該接口,好處在于可以在嵌套類(lèi)內(nèi)編寫(xiě)該接口所有實(shí)現(xiàn)中都要用到的代碼。
嵌套類(lèi)的另一個(gè)用途:編寫(xiě)測(cè)試代碼。 為每個(gè)類(lèi)編寫(xiě)main函數(shù)增加代碼長(zhǎng)度,可以把main放在嵌套類(lèi)內(nèi),要測(cè)試該類(lèi)運(yùn)行該嵌套類(lèi)即可;而在發(fā)布的時(shí)候只要在打包前簡(jiǎn)單的刪除該嵌套類(lèi)的.class文件即可。
多重嵌套的類(lèi)(non-static和static)可以沒(méi)有限制的訪問(wèn)任何外層類(lèi)的所有對(duì)象。
為什么用內(nèi)部類(lèi)?
不是總是直接和接口打交道,有時(shí)候需要用的是接口的實(shí)現(xiàn)。(可以實(shí)現(xiàn)多個(gè)接口,但不能繼承多個(gè)類(lèi))
理由:每個(gè)內(nèi)部類(lèi)可以獨(dú)立繼承自一個(gè)實(shí)現(xiàn),不受outer class是否已經(jīng)繼承另一實(shí)現(xiàn)的限制。從效果上來(lái)說(shuō),inner class提供了多繼承(multiple-inheritance,繼承自多個(gè)類(lèi))的能力,提供了另一種實(shí)現(xiàn)多個(gè)接口的方法(相比多繼承,這個(gè)似乎沒(méi)那么重要,因?yàn)槎嗬^承只能通過(guò)內(nèi)部類(lèi)來(lái)實(shí)現(xiàn))。
額外特性:
1. 內(nèi)部類(lèi)可以有多個(gè)實(shí)例,每個(gè)實(shí)例可以擁有獨(dú)立于outer class對(duì)象的不同信息;
2. 一個(gè)outer class可以有多個(gè)內(nèi)部類(lèi),每個(gè)內(nèi)部類(lèi)可以以不同的方式實(shí)現(xiàn)同一個(gè)接口或者繼承同一個(gè)類(lèi)(參見(jiàn)習(xí)題22,兩個(gè)內(nèi)部類(lèi)不同方式實(shí)現(xiàn)同一個(gè)接口,只有內(nèi)部類(lèi)才能完成這些);
3. 內(nèi)部類(lèi)實(shí)例創(chuàng)建時(shí)間并不受到外部類(lèi)對(duì)象創(chuàng)建的限制;
4. 用內(nèi)部類(lèi)不會(huì)制造"is-a"關(guān)系的混亂,每個(gè)內(nèi)部類(lèi)都是個(gè)實(shí)體。
閉包(closure)和回調(diào)(callback)
閉包是一種可調(diào)用的對(duì)象,它記錄了來(lái)自創(chuàng)建它的作用域的一些信息。
內(nèi)部類(lèi)是一種面向?qū)ο蟮拈]包,不僅包含了外部類(lèi)的信息,而且通過(guò)包含一個(gè)指向外部類(lèi)對(duì)象的引用,可以操作所有成員,包括private。
回調(diào),通過(guò)其它對(duì)象攜帶的信息,可以在稍后的某個(gè)時(shí)刻調(diào)用初始對(duì)象。
Java不支持指針類(lèi)型,不能通過(guò)指針來(lái)實(shí)現(xiàn)回調(diào)。但內(nèi)部類(lèi)提供的閉包是種比較好的解決方案,更靈活,更安全(參見(jiàn)例callbacks)。
- private class Closure implements Incrementable {
- public void increment() {
- // Specify outer-class method, otherwise
- // you’d get an infinite recursion:
- Callee2.this.increment();
- }
- }
回調(diào)的價(jià)值在于靈活性,可以在運(yùn)行時(shí)決定需要調(diào)用的方法。 GUI編程將體現(xiàn)得更明顯。
內(nèi)部類(lèi)與控制框架(control frameworks)
一個(gè)應(yīng)用程序框架(application framework)是指一個(gè)用來(lái)解決一個(gè)特定類(lèi)型問(wèn)題的類(lèi)或類(lèi)的集合。典型的應(yīng)用方法是,繼承其中一個(gè)或多個(gè)類(lèi),重寫(xiě)某些方法。重寫(xiě)方法的代碼將通用解決方案特殊化,來(lái)解決特定問(wèn)題。例如模板函數(shù)模式。 設(shè)計(jì)模式將不變的和變化的事情分開(kāi)。
控制框架是用來(lái)響應(yīng)事件的一類(lèi)特殊的應(yīng)用程序框架 。主要用來(lái)響應(yīng)事件的系統(tǒng)稱(chēng)為事件驅(qū)動(dòng)系統(tǒng)(event-driven system),如GUI。
內(nèi)部類(lèi)使得控制框架的創(chuàng)建和使用變得簡(jiǎn)單 ??刂瓶蚣鼙旧聿话ㄒ刂频氖挛锏奶囟ㄐ畔ⅰ_@些信息在繼承過(guò)程中,由算法的action()部分實(shí)現(xiàn)時(shí)提供??刂瓶蚣苤凶兓氖虑槭歉鞣N事件對(duì)象的不同action,這通過(guò)創(chuàng)建不同event繼承類(lèi)來(lái)實(shí)現(xiàn)。(例event)
控制事件用abstract類(lèi)代替接口?
內(nèi)部類(lèi)在控制框架中兩個(gè)作用:
1. 用來(lái)表示解決問(wèn)題所需的各種不同的action()。
2. 內(nèi)部類(lèi)可以直接訪問(wèn)外部類(lèi)的所有成員,因而使得實(shí)現(xiàn)變得更靈活。
參見(jiàn)greenhouse(溫室)的例子。
內(nèi)部類(lèi)的繼承
內(nèi)部類(lèi)指向outer class object的引用必須初始化,而在它的繼承類(lèi)中并不存在要聯(lián)接的缺省對(duì)象,必須使用特殊的語(yǔ)法明確指出這種關(guān)聯(lián)。
繼承自內(nèi)部類(lèi)的類(lèi)構(gòu)造器不能是默認(rèn)構(gòu)造器,要有個(gè)outer class的引用作為參數(shù),而且必須加上enclosingClassReference.super();語(yǔ)句,編譯才能通過(guò)。
內(nèi)部類(lèi)能override?繼承outer class,像重寫(xiě)方法一樣重寫(xiě)內(nèi)部類(lèi)并不起作用,此時(shí)兩個(gè)內(nèi)部類(lèi)只是兩個(gè)獨(dú)立的實(shí)體??梢燥@式指定內(nèi)部類(lèi)的繼承關(guān)系,然后通過(guò)復(fù)寫(xiě)base inner class的方法,來(lái)實(shí)現(xiàn)多態(tài)。 參見(jiàn)例BigEgg2.
- //: innerclasses/BigEgg2.java
- // Proper inheritance of an inner class.
- import static net.mindview.util.Print.*;
- class Egg2 {
- protected class Yolk {
- public Yolk() { print("Egg2.Yolk()"); }
- public void f() { print("Egg2.Yolk.f()");}
- }
- private Yolk y = new Yolk();
- public Egg2() { print("New Egg2()"); }
- public void insertYolk(Yolk yy) { y = yy; }
- public void g() { y.f(); }
- }
- public class BigEgg2 extends Egg2 {
- public class Yolk extends Egg2.Yolk {
- public Yolk() { print("BigEgg2.Yolk()"); }
- public void f() { print("BigEgg2.Yolk.f()"); }
- }
- public BigEgg2() { insertYolk(new Yolk()); }
- public static void main(String[] args) {
- Egg2 e2 = new BigEgg2();
- e2.g();
- }
- } /* Output:
- Egg2.Yolk()
- New Egg2()
- Egg2.Yolk()
- BigEgg2.Yolk()
- BigEgg2.Yolk.f()
- *///:~
局部?jī)?nèi)部類(lèi)
局部?jī)?nèi)部類(lèi)(local inner class)不能有訪問(wèn)限定符;有訪問(wèn)局部final變量和outer class所有類(lèi)的權(quán)限;可以有命名的構(gòu)造器;在方法外不能訪問(wèn)。
絕大部分情況下,可以用匿名類(lèi)來(lái)替代局部?jī)?nèi)部類(lèi),除非:
1. 需要命名的構(gòu)造器,或者需要重載構(gòu)造器
2. 需要多個(gè)內(nèi)部類(lèi)的對(duì)象
此時(shí)就要用Local Inner class。
【編輯推薦】
- Java的局部?jī)?nèi)部類(lèi)以及final類(lèi)型的參數(shù)和變量
- 沒(méi)有原生數(shù)據(jù)類(lèi)型,Java會(huì)更好嗎?
- 20個(gè)開(kāi)發(fā)人員非常有用的Java功能代碼
- 走進(jìn)Java 7中的模塊系統(tǒng)
- 2009年十大Java技術(shù)解決方案
分享文章:Java編程中的內(nèi)部類(lèi)
文章源于:http://www.dlmjj.cn/article/cdpcihs.html


咨詢
建站咨詢
