Java——內部類的定義以及使用
內部類:在類內部進行其他類結構巢狀操作。
舉慄說明:
class Outter{ private String msg = "Outter中的字串"; //內部類 class Inner{ private String inMsg = "Inner中的字串"; public void fun(){ //直接呼叫外部類的私有屬性 System.out.println(msg); } } public void test(){ //生產內部類物件 Inner in = new Inner(); in.fun(); } } public class Test{ public static void main(String[] args){ Outter out = new Outter(); out.test(); } }
缺點:結構複雜
將Inner類提出來,主方法不變,實現相同的功能:
class Outter{ private String msg = "Outter中的字串"; //因為這裡是private屬性,所以不能直接訪問,需提供getter方法 public String getMsg(){ return this.msg; } public void test(){ //this表示當前物件 Inner in = new Inner(this); in.fun(); } } class Inner{ private String inMsg = "Inner中的字串"; private Outter out; //通過構造方法給Inner內傳入一個Outter類,專業叫做【構造注入】 //此時Outter是Inner內的普通屬性 public Inner(Outter out){ //這裡的Outter out就是一個引數 this.out = out; //為Inner中的out變數初始化 } public void fun(){ System.out.println(out.getMsg()); } } public class Test{ public static void main(String[] args){ Outter out = new Outter(); out.test(); } }
提出來之後我們發現程式碼變得更加麻煩,難理解,此時我們在這裡可以提一下內部類的優點:
- 內部類的優點:
a.內部類與外部類可以方便的訪問彼此的私有域(包含私有方法,私有屬性)
存在私有內部類(靜態,成員均可)
【ArrayList中Node內部類,HashMap中Entry內部類(私有內部類)】
b.內部類是另外一種封裝(保護性),對外部的其他類隱藏(心臟包在人身體內部)
c.內部類可以實現Java單繼承的侷限。
- 使用內部類實現Java的多繼承:
class A{ private String msg = "test"; public String getMsg(){ return msg; } } class B{ private int age = 20; public int getAge(){ return age; } } class C{ class InnerClassA extends A{ public String name(){ return super.getMsg(); } } class InnerClassB extends B{ public int age(){ return super.getAge(); } } public String name(){ return new InnerClassA().name(); } public int age(){ return new InnerClassB().age(); } } public class Test{ public static void main(String[] args){ C c = new C(); System.out.println(c.name()); System.out.println(c.age()); } }
多繼承還是推薦多層繼承。
- 內部類和外部類的關係:(不推薦使用)
1.對於非靜態內部類,內部類的建立需要依賴外部類物件,在沒有外部類例項之前無法建立非靜態內部類。
2.內部類是一個相對獨立的個體,與外部類沒有is-a關係。
3.內部類可以直接訪問外部類的元素(包含私有域),但是外部類不可以直接訪問內部類元素,需要通過內部類的引用間接訪問。
針對於第三點:
class Outter{
private String msg;
private int age;
//-----------------內部類-----------------
class Inner{
public void display(){
msg = "test"; //直接使用
//Outter.this.msg = "test";
age = 20; //直接使用
//Outter.this.age = 20;
System.out.println(msg);
System.out.println(age);
}
}
//---------------- -------------------------
public void test(){
Inner in = new Inner();
in.display();
}
}
public class Test{
public static void main(String[] args){
Outter out = new Outter();
out.test();
}
}
內外部類可以直接訪問彼此的私有屬性:
class Outter{
//-------------------------------------
class Inner{ //1...
private String msg = "InnerClass";
}
//-----------------------------------------
public void test(){
Inner in = new Inner();//2...
System.out.println(in.msg);
}
}
public class Test{
public static void main(String[] args){
Outter out = new Outter();
out.test();
}
}
程式執行結果:
//InnerClass
1.說明了內外部類可以直接訪問彼此的私有屬性,首先必須建立外部類,才能建立內部類,建立內部類的時候就把外部類的物件傳進來了 ,所以可以直接用。
2.外部類訪問內部類需要建立內部類的物件以後才能用,這叫間接使用。
- 建立內部類語法(在外部類外部)
a.建立非靜態內部類
外部類.內部類 內部類引用 = new 外部類().new 內部類();
Outter.Inner in = new Outter().new Inner();
b.建立靜態內部類
外部類.內部類 內部類引用 = new 外部類.內部類();
Outter.Inner in = new Ourtter.Inner();
- 內部類的分類:
1.成員內部類(重點)(成員方法)
a.成員內部類不能存在任何static變數或方法,可以訪問外部類的靜態域。
b.成員內部類是依附外部類的,所以只有先建立了外部類才能建立內部類。(成員內部類不能擁有靜態域,但可以訪問外部靜態域)
class Outter{
private String name = "test";
private static int age = 20;
//-------------------成員內部類----------------
class Inner{
//private static int age = 50;
//成員內部類不能存在static的變數或方法,會報錯:內部類Outter.Inner中的靜態宣告非法。
public void fun(){
System.out.println(name); //可以訪問外部類的靜態或者非靜態屬性
System.out.println(age);
}
}
//------------------------------------------------
}
public class Test{
public static void main(String[] args){
Outter.Inner in = new Outter().new Inner();
in.fun();
}
}
2.靜態內部類(重點)(靜態方法)
和非靜態內部類相比,靜態內部類沒有指向外部的引用。同時,非靜態內部類不能宣告靜態成員,只有靜態內部類才可以宣告靜態成員。
靜態內部類將自動轉換為頂層類(top-levelclass),即它沒有父類,而且不能引用外部類成員或其他內部類成員。當一個內部類不需要引用外部類成員,只需要隱藏在另一個類中時,可以將該內部類宣告為靜態的。
a.靜態內部類的建立不需要依賴外部類,可以直接建立。
b.靜態內部類不可以使用任何外部類的非static域(包含屬性與方法),但是可以存在自己的成員變數。
3.方法內部類(區域性內部類)
方法內部類定義在外部類的方法中,區域性內部類和成員內部類基本一致,只是作用域不同,方法內部類只能在該方法中被使用。
a.方法內部類不允許使用訪問許可權修飾符 public private protected 均不允許。
b.方法內部類對外部完全隱藏除了建立這個類的方法可以訪問它以外,其他地方均不能訪問。
c.方法內部類如果要想使用方法形參,該形參必須使用final宣告(JDK8將形參變為隱式final宣告)
public class Test{
public static void main(String[] args){
final int i = 8;
class person{
public String name;
public void show(){
System.out.println(i);
System.out.println(this.name);
}
}
person p = new person();
p.name = "zhangsan";
p.show();
}
}
程式執行結果:
8
zhangsan
上例中,在main方法中定義了person類,它是一個內部類。內部類方法show訪問了main方法中定義的final型別的區域性變數。其中,方法中內部類只能訪問方法中final型別的區域性變數,而不能訪問其他型別的區域性變數,但可以訪問外部類的資料成員和成員方法。
4.匿名內部類(lamdba表示式前身)
匿名內部類就是一個沒有名字的方法內部類,所以它沒有構造方法(但是如果這個匿名內部類繼承了只含有帶引數構造方法的父類,建立它的時候就必須帶上這些引數,並在實現過程中使用super關鍵字呼叫相應內容)。因此特點與方法內部類完全一樣,除此之外,還有兩個自己的特點:
a.匿名內部類必須繼承一個抽象類或者實現一個介面。
b.匿名內部類沒有構造方法,因為它沒有類名。
匿名類的語法規則:
new interfacename(){...}; 或
new superclassname(){...};
總結:內部類的使用暫時不作為設計的首選。
1.破壞了程式的結構。
2.方便進行私有屬性的訪問。(外部類可以訪問內部類的私有域)
3.如果發現類名稱上出現了“ . “,應當立即想到內部類的概念。