#內(nèi)部類的定義
Java中允許在類中定義另一個(gè)類,這個(gè)定義在其他類內(nèi)部的類就是內(nèi)部類(嵌套類),包含內(nèi)部類的類也被稱為宿主類莽使。
#內(nèi)部類的作用
1.內(nèi)部類提供更好的封裝。內(nèi)部類不允許同一個(gè)包中的其他類訪問該類笙僚。
2.非靜態(tài)內(nèi)部類可以直接訪問外部類的私有數(shù)據(jù)芳肌,但外部類不能訪問內(nèi)部類的實(shí)現(xiàn)細(xì)節(jié)(比如內(nèi)部類的成員變量)。
3.匿名內(nèi)部類適用于創(chuàng)建那些僅需要一次使用的類肋层。
#內(nèi)部類與外部類定義的語(yǔ)法區(qū)別
- 非靜態(tài)內(nèi)部類不能擁有靜態(tài)成員亿笤。
- 內(nèi)部類比外部類可以多使用三個(gè)修飾符:private、protected栋猖、static.
tip:外部類的修飾符只有兩個(gè):public和default净薛。
#內(nèi)部類的種類
- 大部分時(shí)候,內(nèi)部類都被作為成員內(nèi)部類定義蒲拉。
- 成員內(nèi)部類是一種類成員肃拜。
- 局部?jī)?nèi)部類和匿名內(nèi)部類不是類成員痴腌。
tip:類成員有:成員變量,方法燃领,構(gòu)造器和初始化塊士聪。
1.成員內(nèi)部類
-
非靜態(tài)內(nèi)部類
- 非靜態(tài)內(nèi)部類實(shí)例必須寄生在外部類實(shí)例里。
- 非靜態(tài)內(nèi)部類可以直接訪問外部類的私有成員猛蔽。如果我們?cè)谕獠款惖钠渲幸粋€(gè)方法中生成內(nèi)部類的實(shí)例剥悟,那么它們?cè)趦?nèi)存中的形式為:圖1。
圖1:非靜態(tài)內(nèi)部類對(duì)象中保留外部類對(duì)象的引用內(nèi)存示意圖 - 當(dāng)外部類成員變量枢舶、內(nèi)部類成員變量懦胞、內(nèi)部類方法的局部變量同名時(shí),調(diào)用的優(yōu)先級(jí)為:局部變量>內(nèi)部類成員變量>外部類成員變量凉泄。若想使用外部類的成員變量時(shí)可以用類.this.變量名躏尉,若想使用內(nèi)部類的成員變量可以用this.變量名。
- 當(dāng)外部類需要訪問內(nèi)部類的實(shí)例變量時(shí)后众,必須顯式創(chuàng)建內(nèi)部類對(duì)象胀糜。
public class Outer{
private int outProp=9;
class Inner{
private int inProp=5;
public void acessOuterProp(){
//非靜態(tài)內(nèi)部類可以直接訪問外部類的私有成員
System.out.println("外部類的outProp值:"+outProp);
}
}
public void accessInnerProp(){
//外部類不能直接訪問內(nèi)部類的私有成員
//若要訪問必須顯式創(chuàng)建內(nèi)部類對(duì)象
System.out.println("內(nèi)部類的InProp"+new Inner().inProp);
}
public static void main(String[] args){
Outer out=new Outer();
out.accessInnerProp();
}
}
- 外部類的靜態(tài)方法和靜態(tài)代碼塊不能訪問非靜態(tài)內(nèi)部類,包括不能使用非靜態(tài)內(nèi)部類定義變量和創(chuàng)建實(shí)例蒂誉。
-
靜態(tài)內(nèi)部類
如果使用static修飾內(nèi)部類教藻,則這個(gè)內(nèi)部類屬于外部類本身,而不是外部類的對(duì)象右锨。因此使用static修飾的內(nèi)部類被稱為類內(nèi)部類括堤,也叫靜態(tài)內(nèi)部類。
1.靜態(tài)內(nèi)部類可以包含靜態(tài)成員绍移,也可以包含非靜態(tài)成員悄窃。
2.靜態(tài)內(nèi)部類只能訪問外部類的類成員。
3.外部類可以使用內(nèi)部類的類名作為調(diào)用者來(lái)訪問靜態(tài)內(nèi)部類的類成員蹂窖。
4.Java允許在接口中定義內(nèi)部類轧抗,接口內(nèi)部類只能是靜態(tài)內(nèi)部類。
2.局部?jī)?nèi)部類
- 方法里定義的內(nèi)部類叫做局部?jī)?nèi)部類瞬测。它的作用域只在這個(gè)方法內(nèi)横媚,不能在其他地方用。所以局部?jī)?nèi)部類沒有訪問控制符和static修飾月趟。
tip:所有局部變量和局部?jī)?nèi)部類的上一級(jí)程序單元都是方法灯蝴,所以沒有訪問控制符和static修飾。
- 編譯后生成的class文件為:外部類$N局部?jī)?nèi)部類.class孝宗。因?yàn)橐粋€(gè)類中可以有許多同名局部?jī)?nèi)部類绽乔,所以N是為了區(qū)分每個(gè)局部?jī)?nèi)部類。
- 局部?jī)?nèi)部類也可以定義變量碳褒、創(chuàng)建實(shí)例或派生子類折砸,但只能在方法內(nèi)進(jìn)行。
- 局部?jī)?nèi)部類在實(shí)際開發(fā)中應(yīng)用很少沙峻,因?yàn)槲覀兪褂妙惥褪菫榱祟惖膹?fù)用睦授,但是局部?jī)?nèi)部類的作用域?qū)嵲谔×恕?/li>
3.匿名內(nèi)部類
- 匿名內(nèi)部類是沒有類名的類,適合那種只需要用一次的類摔寨。
- 匿名內(nèi)部類在創(chuàng)建時(shí)就會(huì)立即創(chuàng)建一個(gè)實(shí)例去枷。所以匿名內(nèi)部類不能是抽象類。
- 匿名內(nèi)部類必須繼承一個(gè)父類或者實(shí)現(xiàn)一個(gè)接口是复。
- 匿名內(nèi)部類不能定義構(gòu)造器删顶,因?yàn)槟涿麅?nèi)部類沒有類名。通過實(shí)現(xiàn)接口創(chuàng)建的匿名內(nèi)部類只有隱式的無(wú)參構(gòu)造器(其實(shí)是繼承自O(shè)bject的無(wú)參構(gòu)造器)淑廊,通過繼承父類創(chuàng)建的匿名內(nèi)部類擁有和父類相似的構(gòu)造器(形參列表相同)逗余。
tip:通過繼承父類創(chuàng)建的匿名內(nèi)部類的無(wú)參構(gòu)造方法是父類的構(gòu)造方法。
- Java要求被局部?jī)?nèi)部類季惩、匿名內(nèi)部類訪問的局部變量必須使用final修飾录粱。在Java8之后可以省略final修飾,但是被調(diào)用的局部變量還是會(huì)變成final變量(Java8新增的effectively final功能)画拾。
tip:局部變量離開方法后就會(huì)失效啥繁,但匿名內(nèi)部類不會(huì),所以需要使用final修飾變量青抛。用final修飾局部變量會(huì)使局部變量生命周期跟這個(gè)類一樣旗闽。所以用final修飾后就不會(huì)出現(xiàn)匿名內(nèi)部類想要用局部變量時(shí)局部變量被GC回收的尷尬情況。
#使用內(nèi)部類
1.在外部類中使用內(nèi)部類蜜另。
與平常使用類沒有太大區(qū)別适室,注意不要在靜態(tài)成員中使用非靜態(tài)內(nèi)部類即可。
2.在外部類外使用非靜態(tài)內(nèi)部類蚕钦。
- 在外部類外使用非靜態(tài)內(nèi)部類時(shí)额湘,只能在其訪問控制符對(duì)應(yīng)的權(quán)限內(nèi)使用,非靜態(tài)內(nèi)部類不能被private修飾堕汞。
- 定義變量的語(yǔ)法如下: 外部類.內(nèi)部類 變量名;
OutClass.InnerClass varName; - 創(chuàng)建對(duì)象的語(yǔ)法如下:外部類.new 內(nèi)部類的構(gòu)造器;
OutClass.new InnerClass();
tip:非靜態(tài)內(nèi)部類的構(gòu)造器必須由外部類的對(duì)象調(diào)用躁劣。
-
當(dāng)非靜態(tài)內(nèi)部類被繼承時(shí)的用法。
public class SubClass extends Out.In{
//構(gòu)造器
public SubClass(Out out){
//這里super是SubClass的父類邮屁,所以是Out.In類
//通過外部類的對(duì)象out調(diào)用內(nèi)部類的構(gòu)造器
out.super();
}
}
- 如果有一個(gè)內(nèi)部類子類的對(duì)象存在整袁,則一定有一個(gè)外部類對(duì)象。
3.在外部類外使用靜態(tài)內(nèi)部類
- 在外部類外使用靜態(tài)內(nèi)部類時(shí)無(wú)需創(chuàng)建外部類對(duì)象佑吝。
- 定義變量的語(yǔ)法如下: 外部類.內(nèi)部類 變量名;
OutClass.InnerClass varName; - 創(chuàng)建對(duì)象的語(yǔ)法如下:外部類.內(nèi)部類的構(gòu)造器;
OutClass.InnerClass();
tip:靜態(tài)內(nèi)部類的構(gòu)造器不需要外部類對(duì)象調(diào)用坐昙。
- 相比之下,使用靜態(tài)內(nèi)部類比非靜態(tài)內(nèi)部類方便的多芋忿,所以當(dāng)需要使用內(nèi)部類時(shí)優(yōu)先考慮使用靜態(tài)內(nèi)部類炸客。
#總結(jié)
為什么Java要引入內(nèi)部類的概念呢疾棵?
那是因?yàn)閮?nèi)部類具有一般類不具備的優(yōu)點(diǎn)。
- 內(nèi)部類提供更好的封裝痹仙。內(nèi)部類可以使用private或protected修飾而外部類不行是尔。
- 內(nèi)部類可以實(shí)現(xiàn)多繼承。Java不像C++允許多繼承开仰,但是用內(nèi)部類可以實(shí)現(xiàn)Java中的多繼承拟枚。在一個(gè)類中可以用兩個(gè)或多個(gè)內(nèi)部類繼承不同的父類實(shí)現(xiàn)多繼承。
通過以上學(xué)習(xí)众弓,我們對(duì)Java中內(nèi)部類有了一些了解恩溅,這對(duì)以后我們學(xué)習(xí)Java8新增的Lambda表達(dá)式有一些概念性的鋪墊,關(guān)于Java中的Lambda表達(dá)式我以后會(huì)更新谓娃。希望這篇文章能對(duì)學(xué)習(xí)內(nèi)部類的你們有一些小幫助脚乡。