眾所周知,外部頂級類的類名需和類文件名相同,只能使用public和default。而內(nèi)部類是指在外部類的內(nèi)部再定義一個類,類名不需要和文件名相同。內(nèi)部類可以是靜態(tài)static的,也可用public,default(包限定),protected和private修飾。
內(nèi)部類:
概念:
我們所說的內(nèi)部類,官方的叫法是嵌套類(Nested Classes)。嵌套類包括靜態(tài)內(nèi)部類(Static Nested Classes)和內(nèi)部類(Inner Classes)。而非靜態(tài)內(nèi)部類分為成員內(nèi)部類,局部內(nèi)部類(Local Classes)和匿名內(nèi)部類(Anonymous Classes)。

內(nèi)部類是一個編譯是的概念,一旦編譯成功,就會成為完全不同的兩個類,分別為outer.class和outer$inner.class類。所以內(nèi)部類的成員變量/方法名可以和外部類的相同。
內(nèi)部類有什么作用?
1.內(nèi)部類可以很好的實現(xiàn)隱藏
一般的非內(nèi)部類,是不允許有 private 與protected權(quán)限的,但內(nèi)部類可以
2.內(nèi)部類擁有外圍類的所有元素的訪問權(quán)限 (private修飾也能訪問)
3.可是實現(xiàn)多重繼承 (讓多個內(nèi)部類分別繼承多個其他類,使外部類可以同時獲取多個其他類的屬性)
4.可以避免修改接口而實現(xiàn)同一個類中兩種同名方法的調(diào)用。(外部類繼承,讓內(nèi)部類實現(xiàn)接口)
靜態(tài)內(nèi)部類:
形如:
public class OuterClass {
private String name;
static class StaticInerCls{
private String name;
}
}
靜態(tài)內(nèi)部類除了訪問權(quán)限修飾符比外圍類多以外, 和外圍類沒有區(qū)別, 只是代碼上將靜態(tài)內(nèi)部類組織在了外部類里面。
創(chuàng)建靜態(tài)內(nèi)部類:以Class.Iner的形式
OuterClass.StaticInerCls staticInerCls = new OuterClass.StaticInerCls();
靜態(tài)內(nèi)部類與普通內(nèi)部類的區(qū)別
- 靜態(tài)內(nèi)部類不持有外部類的引用 在普通內(nèi)部類中,我們可以直接訪問外部類的屬性、方法,即使是private類型也可以訪問,這是因為內(nèi)部類持有一個外部類的引用,可以自由訪問。而靜態(tài)內(nèi)部類,則只可以訪問外部類的靜態(tài)方法和靜態(tài)屬性(即使是private權(quán)限也能訪問,這是由其代碼位置所決定的),其他則不能訪問。
- 靜態(tài)內(nèi)部類不依賴外部類 普通內(nèi)部類與外部類之間是相互依賴的關(guān)系,內(nèi)部類實例不能脫離外部類實例,也就是說它們會同生同死,一起聲明,一起被垃圾回收器回收。而靜態(tài)內(nèi)部類是可以獨立存在的,即使外部類消亡了,靜態(tài)內(nèi)部類還是可以存在的。
非靜態(tài)內(nèi)部類:
非靜態(tài)內(nèi)部類能訪問外部類的一切成員, 包括私有成員。外部類雖然不能直接訪問內(nèi)部類的成員, 但是可以通過內(nèi)部類的實例訪問內(nèi)部類的私有成員。
成員內(nèi)部類:
形如:
public class OuterCls {
private String name;
public String getName(){
return name;
}
class InerCls{
private String name;
public String getName(){
return name;
}
}
}
成員內(nèi)部類可以直接使用外部類的所有成員和方法,即使是private修飾的。而外部類要訪問內(nèi)部類的所有成員變量和方法,內(nèi)需要通過內(nèi)部類的對象來獲取。(誰叫它是親兒子呢?) 要注意的是,成員內(nèi)部類不能含有static的變量和方法。因為成員內(nèi)部類需要先創(chuàng)建了外部類,才能創(chuàng)建它自己的。
創(chuàng)建內(nèi)部類對象方法,以object.new Iner的形式:
OuterCls outerCls = new OuterCls();
OuterCls.InerCls inerCls = outerCls.new InerCls();
成員內(nèi)部類不能有static修飾的成員,但是卻允許定義常量。
public class OuterClass {
private String name;
static class StaticInerCls{
private String name;
}
class InerCls{
private String name;
private static int id; //不允許,會報錯
private static final int TYPE = 0; //允許
}
}
靜態(tài)類的主要特性:
1:僅包含靜態(tài)成員。
2:無法實例化。
3:是密封的。
4:不能包含實例構(gòu)造函數(shù)。
為什么普通內(nèi)部類不能有靜態(tài)變量
1.成員內(nèi)部類 之所以叫做成員 就是說他是類實例的一部分 而不是類的一部分。
2.結(jié)構(gòu)上來說 他和你聲明的成員變量是一樣的地位 一個特殊的成員變量 而靜態(tài)的變量是類的一部分和實例無關(guān)。
3.非靜態(tài)內(nèi)部類能訪問外部類的一切屬性;靜態(tài)內(nèi)部類只能訪問外部類的靜態(tài)屬性。
內(nèi)部類中要想訪問外部類的非靜態(tài)成員,需要使用外部類進行引導(dǎo):外部內(nèi)名.this.屬性的名稱;想要訪問外部類靜態(tài)成員時,可以省略this:外部類名.屬性的名稱。
/**
* 獲取外部類靜態(tài)屬性
* @return
*/
public String getParentName() {
return OuterClass.staticName;
}
/**
* 獲取外部類非靜態(tài)屬性
* @return
*/
public String getParentName() {
return OuterClass.this.name;
}
局部內(nèi)部類:
指內(nèi)部類定義在方法體內(nèi),只能在該方法或條件的作用域內(nèi)才能使用,退出這寫作用域就無法引用。
作為非靜態(tài)內(nèi)部類的一種特殊形式, 非靜態(tài)內(nèi)部類的所有限制對局部類同樣成立。局部類不僅可以訪問外部類的所有成員,還可以訪問方法體的局部變量,但必須是final修飾的局部變量。
為什么局部類訪問局部變量,變量必須加上final?
場景:
Object method(){
int localVariable = 0;
class Inner{
void println(){
System.out.println("localVariable " + localVariable++);
}
}
Object in = new Inner();
return in;
}
}
這里的localVariable會變紅,提示需要給localVariable變量加final修飾。
解析:這是作用域的問題。在方法method執(zhí)行完成后,局部變量value就失效了,而在new Inner()產(chǎn)生的in對象還存在obj的引用,這樣對象就訪問了一個不存在的變量,是不允許的。iner還存在,在外面和后續(xù)調(diào)用該局部變量時,這個局部變量可能已經(jīng)失效了。但為什么加上final就可以保證能訪問呢?這里Java采用了一種copy local variable的方法實現(xiàn),定義為final的變量,會拷貝一份存到局部內(nèi)部類中,后續(xù)使用持續(xù)維護這個對象在生命周期內(nèi),所以可以繼續(xù)訪問。
修改之后:
Object method(){
final int[] localVariable = {0};
class Inner {
void println(){
System.out.println("localVariable " + localVariable[0]++);
}
}
Object in = new Inner();
return in;
}
還有一種解釋是局部變量可能在方法中值被修改,而導(dǎo)致內(nèi)部類得到的值不一致,于是用final來讓該引用不可改變。
注:final可以修飾的范圍有類,方法,屬性。修飾類,該類不可以被繼承;修飾方法,該方法不可以被子類重寫;修飾變量,該變量值不能被修改。
匿名內(nèi)部類:
定義:
new抽象類或者是接口,能夠獲得一個抽象類或者是接口的一個實現(xiàn)類對象,這個實現(xiàn)類對象沒有名字,所以稱之為匿名內(nèi)部類。本質(zhì)是一個繼承了類或者實現(xiàn)了接口的子類匿名對象。
匿名內(nèi)部類的條件:
1.匿名內(nèi)部類不能有構(gòu)造方法。
2.匿名內(nèi)部類不能定義任何靜態(tài)成員、方法和類。
3.匿名內(nèi)部類不能是public,protected,private,static。
4.只能創(chuàng)建匿名內(nèi)部類的一個實例。
5.一個匿名內(nèi)部類一定是在new的后面,用其隱含實現(xiàn)一個接口或?qū)崿F(xiàn)一個類。
6.因匿名內(nèi)部類為局部內(nèi)部類,所以局部內(nèi)部類的所有限制都對其生效。
/**
* 匿名內(nèi)部類
*/
private Thread thread = new Thread(new Runnable() {
@Override
public void run() {
}
});
Runnable只是一個接口,卻可以直接new出一個實例,創(chuàng)建的對象是這個接口的一個實現(xiàn)類對象,沒有名字,只能使用一次。
參考:https://juejin.cn/post/6986449929426173965