Java內部類(成員內部類、靜態內部類、方法內部類、匿名內部類)
內部類 內部類是定義在一個類內部進行其他類結構的巢狀的操作。 為什麼存在內部類?1.首先看下內部類和不用內部類實現相同功能的程式碼: 不用內部類
//////不用內部類 class Outter { private String msg="pick"; public String Getmsg() { return msg; } public void fun()//3 { Inner in=new Inner(this);//4 in.Print(); } } class Inner { private Outter out; public void Print() { System.out.println(out.Getmsg()); } public Inner(Outter out) { this.out=out; } } public class Out { public static void main(String[] args) { Outter out=new Outter();//1 out.fun();//2 } }
用內部類
/////用內部類 class Outter { private String msg="pick"; class Inner { public void Print() { System.out.println(msg); //可以發現內部類可以直接訪問外部類屬性 } } //在外部類中定義一個方法,該方法負責產生內部類物件,並呼叫Print public void fun() { Inner in=new Inner(); in.Print(); } } public class Out { public static void main(String[] args) { Outter out=new Outter(); out.fun(); } }
可以發現兩種方法實現相同的功能,用或不用內部類程式碼複雜程度不同,直接原因是內部類可以直接訪問外部類私有屬性。 2.內部類可以模擬實現多繼承:
///內部類可以實現多繼承 class A { private String name="pick"; public String Getname() { return name; } } class B { private int age=18; public int Getage() { return age; } } class C { class ExtendA extends A //ExtendA 繼承A { public String Name() { return new A().Getname(); // 返回父類A的屬性name } } class ExtendB extends B // ExtendB 繼承B { public int Age() { return new B().Getage();//返回父類B的屬性年齡 } } public String name() { return new ExtendA().Name(); //返回內部類的Name,相當於A的name } public int age() { return new ExtendB().Age(); //返回內部類的Age,相當於B的age } //C類現在既有A的屬性name,也有B的屬性age,模擬實現了多繼承 } public class Out { public static void main(String[] args) { C c=new C(); System.out.println(c.name()); //pick System.out.println(c.age()); //18 } }
3.內部類是另外一種封裝,內部類具有保護性,對外部其他類不可見: 在主類中無法直接訪問或者建立內部類 所以內部類存在原因如下:
-
內部類可以直接訪問外部類的私有域(包括私有屬性和私有方法)
-
內部類是另外一種封裝(保護性),對外部的其他類隱藏(心臟包在人身體內部)
-
內部類可以實現Java單繼承的侷限。 但是內部類也存在缺點:結構複雜。 建立內部類在外部類內部建立內部類 內部類 內部類引用=new 內部類(); Inner in=new Inner( ); (可參考上文中不用內部類程式碼) 在外部類外部建立內部類
-
在外部類外部建立非靜態內部類
外部類.內部類 內部類引用 =new 外部類( ).new 內部類( );
Outter.Inner in =new Outter( ).new Inner( );
//在外部類外部建立非靜態內部類
class Outter
{
class Inner
{
public String name="pick";
public void show()
{
System.out.println("hello day");
}
}
}
public class Out
{
public static void main(String[] args)
{
Outter.Inner in=new Outter().new Inner();
System.out.println(in.name); //pick
in.show(); //hello day
}
}
- 在外部類外部建立靜態內部類
外部類.內部類 內部類引用=new 外部類.內部類( ); Outter.Inner in=new Outter( ).Inner( );
//建立非靜態內部類
class Outter
{
static class Inner
{
public String name="pick";
public void show()
{
System.out.println("hello day");
}
}
}
public class Out
{
public static void main(String[] args)
{
Outter.Inner in=new Outter.Inner();
System.out.println(in.name); //pick
in.show(); //hello day
}
}
內部類與外部類的關係
- 內部類是一個相對獨立的個體,與外部類沒有is-a關係;
- 對於非靜態內部類,內部類的建立需要依賴外部類物件,在外部類沒有例項化前無法建立非靜態內部類。
- 內部類可以直接訪問外部類的元素(包括私有域),但是外部類不可以直接訪問內部類元素,需要通過內部類的引用間接訪問。 內部類對外部類的直接訪問:
class Outter
{
private String name;
private int age;
class Inner
{
public Inner()
{
Outter.this.name="pick"; //如果用this,必須先找到外部類
age=18;
}
public void fun()
{
System.out.println(name);
}
}
}
public class Out
{
public static void main(String[] args)
{
Outter.Inner in=new Outter().new Inner();
in.fun();
}
}
外部類通過內部類的引用間接訪問內部類元素:
//外部類訪問內部類
class Outter
{
class Inner
{
private String name;
public void print()
{
System.out.println("Inner");
}
}
public void show()
{
Inner in=new Inner();
System.out.println(in.name); //內部類的引用間接訪問內部類元素
//System.out.println(name); //錯誤,不能直接訪問
in.print();
}
}
內部類的分類
成員內部類(類比成員方法)
-
成員內部類不能存在任何static變數或方法,可以訪問外部類的靜態域;
-
成員內部類依賴外部類,只有先建立外部類才能建立內部類;在編譯完成之後會隱含的儲存一個引用,該引用指向建立它的外部類; 靜態內部類(類比靜態方法)
-
使用static修飾的內部類為靜態內部類
-
靜態內部類沒有指向外部類的引用,所以靜態內部類的建立不需要依賴外部類,可以直接建立;
-
靜態內部類不可以使用任何外部類的非static域(包括屬性與方法),可以使用外部類的static域,但是可以存在自己的成員變數 靜態內部類不可以訪問外部成員變數,但是可以擁有成員變數; 成員內部類不可以擁有靜態變數,但可以訪問外部靜態變數;因為靜態變數和物件無關,是在編譯時載入類存在的。 方法內部類
////方法內部類
class Outter
{
private int num=10;
public void func(int tmp) //該tmp是final宣告,只是JDK8將形參變為隱式final宣告
{
//方法內部類
class Inner
{
public void show()
{
//++tmp; //不可以修改,tmp是final宣告
System.out.println(tmp);
System.out.println(num); //方法內部類可以訪問方法外的屬性,但是方法外訪問不了方法內部類屬性
}
}
new Inner().show();
}
}
public class Out
{
public static void main(String[] args)
{
Outter out=new Outter();
out.func(19); // 19 10
}
}
- 方法內部類不允許使用訪問許可權修飾符,public/private/protected均不允許;
- 方法內部類對外部完全隱藏,除了建立這個類的方法可以訪問它以外,其他地方均不能訪問;
- 方法內部類如果想要使用方法形參,該形參必須使用final宣告。(JDK8將形參變為隱式final宣告) 建立方法內部類 的方法形參是final宣告,不可以修改:
匿名內部類(lamdba表示式前身) 匿名內部類就是一個沒有名字的方法內部類。因此特點與方法內部類完全一樣,除此之外,還有兩個自己的特點:
- 匿名內部類必須繼承一個抽象類或者實現一個介面;
- 匿名內部類沒有構造方法,因為它沒有類名 。但是方法內部類有構造方法。
//////匿名內部類:是特殊的方法內部類
interface Myinterface //宣告一個介面
{
void print();//抽象方法:沒有方法體
}
class Outter
{
private int num=5;
public void func(int tmp)
{
//匿名內部類,匿名的實現了Myinterface介面
new Myinterface()
{
public void print()
{
System.out.println("匿名實現Myinterface介面");
System.out.println(tmp);
System.out.println(num);
}
}.print();
}
}
public class Out
{
public static void main(String[] args)
{
Outter out=new Outter();
out.func(10); // 匿名實現Myinterface介面 10 5
}
}
注:如果發現類名稱上出現了“.”,就是內部類。