您好,登錄后才能下訂單哦!
怎么理解Java編程中的內(nèi)部類,針對(duì)這個(gè)問(wèn)題,這篇文章詳細(xì)介紹了相對(duì)應(yīng)的分析和解答,希望可以幫助更多想解決這個(gè)問(wèn)題的小伙伴找到更簡(jiǎn)單易行的方法。
內(nèi)部類:在其它類內(nèi)定義的類,不同于組合。雖然看上去象某種代碼隱藏機(jī)制,但可以實(shí)現(xiàn)更多功能 -了解包含它的類并可與之交換數(shù)據(jù),而且內(nèi)部類的代碼可以更優(yōu)雅、清晰。
內(nèi)部類定義:包含在其它類內(nèi)。使用與非內(nèi)部類沒(méi)有太大區(qū)別。
典型用法:outer class通過(guò)方法返回inner class的引用。
區(qū)別之一:內(nèi)部類名嵌套在外部類(outer class)內(nèi),在Out class的non-static方法之外用OuterClassName.InnerClassName的形式定義內(nèi)部類對(duì)象。
注意,非static內(nèi)部類只能在Out class的non-static方法中生成對(duì)象;在其它類中,也必須使用Out class的外部類對(duì)象實(shí)例。這就保證了下面所說(shuō)的鏈接問(wèn)題。
區(qū)別之二:內(nèi)部類可以為private和protected。
Inner Class只是一種名稱隱藏(name-hiding)和組織代碼方式?NO。
內(nèi)部類對(duì)象有一個(gè)到創(chuàng)建它的外部類對(duì)象的鏈接(link to the enclosing object that made it),因而可以直接的、沒(méi)有任何限制地訪問(wèn)該外部類對(duì)象的成員,而且內(nèi)部類可以訪問(wèn)outer class的所有成員(包括private)(C++的嵌套類沒(méi)有這個(gè)特性);而outer class訪問(wèn)inner class的成員,必須創(chuàng)建Inner class的對(duì)象,可以訪問(wèn)任何成員(包括private)。
內(nèi)部類對(duì)象中隱式包含了一個(gè)外部類對(duì)象的引用。內(nèi)部類對(duì)象構(gòu)建需要outer class對(duì)象的引用,如果沒(méi)有,編譯報(bào)錯(cuò)(非靜態(tài)inner class)。
.this和.new:前者用來(lái)返回Outer class引用,編譯期可知道和檢查正確類型,無(wú)運(yùn)行時(shí)開(kāi)銷;后者用來(lái)由outer class對(duì)象創(chuàng)建其內(nèi)部類的對(duì)象,OutClassObject.new InnerClassName ()(注意,不能用outClassObj.new OutClassName.InnerClassName())。
嵌套類(nested class):static inner class,其對(duì)象創(chuàng)建不需要outer class對(duì)象引用,也可在static方法中創(chuàng)建。
內(nèi)部類與upcasting
類實(shí)現(xiàn)了接口(interface),其它方法就可以用該interface作為參數(shù),而不一定必須用該類(包括類對(duì)象定義)(類似繼承)。可以利用upcasting->interface。
upcasting內(nèi)部類->基類或者接口(尤其是后者),使內(nèi)部類有了用武之地。實(shí)現(xiàn)接口內(nèi)部類可以完全不可見(jiàn)、不可用(通過(guò)private或protected),所獲得的只是基類或接口的引用(通過(guò)private,無(wú)法進(jìn)行downcasting,protected,同一個(gè)包內(nèi),或者繼承類可以進(jìn)行downcasting),方便隱藏實(shí)現(xiàn)細(xì)節(jié)。
接口成員自動(dòng)為public
private內(nè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)的類輔助解決復(fù)雜的問(wèn)題
inner class形式
1. 方法內(nèi)的內(nèi)部類; 2. 方法中的一個(gè)作用域內(nèi)的內(nèi)部類; 3. 實(shí)現(xiàn)接口的匿名內(nèi)部類; 4. 繼承的匿名內(nèi)部類(基類含有參的構(gòu)造器); 4. 進(jìn)行成員初始化的匿名內(nèi)部類; 5. 使用實(shí)例初始化塊進(jìn)行構(gòu)造的匿名內(nèi)部類(匿名類沒(méi)有構(gòu)造器)。
局部?jī)?nèi)部類(local inner class) :在方法內(nèi)或方法的一個(gè)作用域中定義的內(nèi)部類。局部?jī)?nèi)部類在域外不可見(jiàn)并不代表其對(duì)象也不可用。條件域內(nèi)定義的內(nèi)部類不代表它是條件創(chuàng)建的。
匿名內(nèi)部類(anonymous inner class) :new T(){...}; {...}為匿名內(nèi)部類的定義,";"不可少(;只是該語(yǔ)句的結(jié)束,而不是用來(lái)表示匿名內(nèi)部類的結(jié)束,所以沒(méi)有什么特殊的地方),創(chuàng)建一個(gè)繼承自T的匿名類的對(duì)象,得到的引用可自動(dòng)upcast to T。是前面定義內(nèi)部類的一種簡(jiǎn)寫(xiě),只是該類沒(méi)有名稱。
前面是基類構(gòu)造器為默認(rèn)構(gòu)造器的情況,當(dāng)基類構(gòu)造器有參數(shù)時(shí):new T(args){...};此時(shí)會(huì)調(diào)用基類相應(yīng)構(gòu)造器。
匿名內(nèi)部類初始化 :當(dāng)需要用到外部定義類的對(duì)象時(shí),傳遞的引用參數(shù)必須為final,否則編譯報(bào)錯(cuò);匿名類不能有命名的構(gòu)造器(當(dāng)然不能,類本身就沒(méi)有名字),可以通過(guò)實(shí)例初始化(instance initialization)來(lái)完成構(gòu)造器的功能。由于實(shí)例初始化不能重載(不代表只能有一個(gè)Instance initialization clause),所以匿名內(nèi)部類只能有一個(gè)構(gòu)造器。
匿名內(nèi)部類只能在繼承類和實(shí)現(xiàn)接口中2選一,且只能實(shí)現(xiàn)一個(gè)接口。
prefer classes to interfaces. (寧愿選擇類,而不是接口?)
嵌套類(nested class):static inner class。有點(diǎn)類似C++嵌套類的概念,但Java的嵌套類可以訪問(wèn)outer class的所有成員(包括private,當(dāng)然只能通過(guò)外部類對(duì)象訪問(wèn)non-static成員)。
1. 不需要通過(guò)outer class對(duì)象來(lái)創(chuàng)建嵌套類對(duì)象(.new不可用?);
2. 不能通過(guò)嵌套類對(duì)象訪問(wèn)non-static outer class對(duì)象(意思是像非嵌套類那樣直接訪問(wèn));
3. 嵌套類對(duì)象中不包含outer class對(duì)象引用(.this不可用)。
4. 非嵌套內(nèi)部類不能有static成員、方法和嵌套類(fields、methods級(jí)別必須與class本身一致,non-static不能含有static,non-static、static內(nèi)可以含有non-static)。
嵌套類可以位于接口內(nèi)部,不違反接口的規(guī)則(不能定義接口實(shí)例?),只代表把嵌套類位于接口的命名空間下,位于接口內(nèi)部的類自動(dòng)為public static(public嵌套類),而且嵌套類本身就可以實(shí)現(xiàn)該接口,好處在于可以在嵌套類內(nèi)編寫(xiě)該接口所有實(shí)現(xiàn)中都要用到的代碼。
嵌套類的另一個(gè)用途:編寫(xiě)測(cè)試代碼。 為每個(gè)類編寫(xiě)main函數(shù)增加代碼長(zhǎng)度,可以把main放在嵌套類內(nèi),要測(cè)試該類運(yùn)行該嵌套類即可;而在發(fā)布的時(shí)候只要在打包前簡(jiǎn)單的刪除該嵌套類的.class文件即可。
多重嵌套的類(non-static和static)可以沒(méi)有限制的訪問(wèn)任何外層類的所有對(duì)象。
為什么用內(nèi)部類?
不是總是直接和接口打交道,有時(shí)候需要用的是接口的實(shí)現(xiàn)。(可以實(shí)現(xiàn)多個(gè)接口,但不能繼承多個(gè)類)
理由:每個(gè)內(nèi)部類可以獨(dú)立繼承自一個(gè)實(shí)現(xiàn),不受outer class是否已經(jīng)繼承另一實(shí)現(xiàn)的限制。從效果上來(lái)說(shuō),inner class提供了多繼承(multiple-inheritance,繼承自多個(gè)類)的能力,提供了另一種實(shí)現(xiàn)多個(gè)接口的方法(相比多繼承,這個(gè)似乎沒(méi)那么重要,因?yàn)槎嗬^承只能通過(guò)內(nèi)部類來(lái)實(shí)現(xiàn))。
額外特性:
1. 內(nèi)部類可以有多個(gè)實(shí)例,每個(gè)實(shí)例可以擁有獨(dú)立于outer class對(duì)象的不同信息;
2. 一個(gè)outer class可以有多個(gè)內(nèi)部類,每個(gè)內(nèi)部類可以以不同的方式實(shí)現(xiàn)同一個(gè)接口或者繼承同一個(gè)類(參見(jiàn)習(xí)題22,兩個(gè)內(nèi)部類不同方式實(shí)現(xiàn)同一個(gè)接口,只有內(nèi)部類才能完成這些);
3. 內(nèi)部類實(shí)例創(chuàng)建時(shí)間并不受到外部類對(duì)象創(chuàng)建的限制;
4. 用內(nèi)部類不會(huì)制造"is-a"關(guān)系的混亂,每個(gè)內(nèi)部類都是個(gè)實(shí)體。
閉包(closure)和回調(diào)(callback)
閉包是一種可調(diào)用的對(duì)象,它記錄了來(lái)自創(chuàng)建它的作用域的一些信息。
內(nèi)部類是一種面向?qū)ο蟮拈]包,不僅包含了外部類的信息,而且通過(guò)包含一個(gè)指向外部類對(duì)象的引用,可以操作所有成員,包括private。
回調(diào),通過(guò)其它對(duì)象攜帶的信息,可以在稍后的某個(gè)時(shí)刻調(diào)用初始對(duì)象。
Java不支持指針類型,不能通過(guò)指針來(lái)實(shí)現(xiàn)回調(diào)。但內(nè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)部類與控制框架(control frameworks)
一個(gè)應(yīng)用程序框架(application framework)是指一個(gè)用來(lái)解決一個(gè)特定類型問(wèn)題的類或類的集合。典型的應(yīng)用方法是,繼承其中一個(gè)或多個(gè)類,重寫(xiě)某些方法。重寫(xiě)方法的代碼將通用解決方案特殊化,來(lái)解決特定問(wèn)題。例如模板函數(shù)模式。 設(shè)計(jì)模式將不變的和變化的事情分開(kāi)。
控制框架是用來(lái)響應(yīng)事件的一類特殊的應(yīng)用程序框架 。主要用來(lái)響應(yīng)事件的系統(tǒng)稱為事件驅(qū)動(dòng)系統(tǒng)(event-driven system),如GUI。
內(nèi)部類使得控制框架的創(chuàng)建和使用變得簡(jiǎn)單 ??刂瓶蚣鼙旧聿话ㄒ刂频氖挛锏奶囟ㄐ畔?。這些信息在繼承過(guò)程中,由算法的action()部分實(shí)現(xiàn)時(shí)提供??刂瓶蚣苤凶兓氖虑槭歉鞣N事件對(duì)象的不同action,這通過(guò)創(chuàng)建不同event繼承類來(lái)實(shí)現(xiàn)。(例event)
控制事件用abstract類代替接口?
內(nèi)部類在控制框架中兩個(gè)作用:
1. 用來(lái)表示解決問(wèn)題所需的各種不同的action()。
2. 內(nèi)部類可以直接訪問(wèn)外部類的所有成員,因而使得實(shí)現(xiàn)變得更靈活。
參見(jiàn)greenhouse(溫室)的例子。
內(nèi)部類的繼承
內(nèi)部類指向outer class object的引用必須初始化,而在它的繼承類中并不存在要聯(lián)接的缺省對(duì)象,必須使用特殊的語(yǔ)法明確指出這種關(guān)聯(lián)。
繼承自內(nèi)部類的類構(gòu)造器不能是默認(rèn)構(gòu)造器,要有個(gè)outer class的引用作為參數(shù),而且必須加上enclosingClassReference.super();語(yǔ)句,編譯才能通過(guò)。
內(nèi)部類能override?繼承outer class,像重寫(xiě)方法一樣重寫(xiě)內(nèi)部類并不起作用,此時(shí)兩個(gè)內(nèi)部類只是兩個(gè)獨(dú)立的實(shí)體。可以顯式指定內(nè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)部類
局部?jī)?nèi)部類(local inner class)不能有訪問(wèn)限定符;有訪問(wèn)局部final變量和outer class所有類的權(quán)限;可以有命名的構(gòu)造器;在方法外不能訪問(wèn)。
絕大部分情況下,可以用匿名類來(lái)替代局部?jī)?nèi)部類,除非:
1. 需要命名的構(gòu)造器,或者需要重載構(gòu)造器
2. 需要多個(gè)內(nèi)部類的對(duì)象
此時(shí)就要用Local Inner class。
關(guān)于怎么理解Java編程中的內(nèi)部類問(wèn)題的解答就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,如果你還有很多疑惑沒(méi)有解開(kāi),可以關(guān)注億速云行業(yè)資訊頻道了解更多相關(guān)知識(shí)。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。