問題描述
Java內部類有什麼好處?爲什麼需要內部類?
解答
首先舉一個簡單的例子,如果你想實現一個接口,但是這個接口中的一個方法和你構想的這個類中的一個方法的名稱,參數相同,你應該怎麼辦?
這時候,你可以建一個內部類實現這個接口。由於內部類對外部類的所有內容都是可訪問的,所以這樣做可以完成所有你直接實現這個接口的功能。
不過你可能要質疑,更改一下方法的不就行了嗎?
的確,以此作爲設計內部類的理由,實在沒有說服力。
真正的原因是這樣的,Java中的內部類和接口加在一起,可以解決一個問題,此問題經常被C++程序員抱怨,那就是Java中沒有多繼承。
實際上,C++的多繼承設計起來很複雜,而Java通過內部類加上接口,可以很好的實現多繼承的效果。
一、常規內部類
- 常規內部類沒有用static修飾且定義在在外部類類體中。
- 常規內部類中的方法可以直接使用外部類的實例變量和實例方法。
- 在常規內部類中可以直接用內部類創建對象
具體代碼如下:
public class MyOuter {
private int x = 100;
// 創建內部類
class MyInner {
private String y = "Hello!";
public void innerMethod() {
System.out.println("內部類中 String =" + y);
System.out.println("外部類中的x =" + x);// 直接訪問外部類中的實例變量x
outerMethod();
System.out.println("x is" + MyOuter.this.x);
}
}
public void outerMethod() {
x++;
}
public void makeInner() {
//在外部類方法中創建內部類實例
MyInner in = new MyInner();
}
/**
* @param args
*/
public static void main(String[] args) {
MyOuter mo = new MyOuter();
// 使用外部類構造方法創建mo對象
MyOuter.MyInner inner = mo.new MyInner();//常規內部類需要通過外部類的實例才能創建對象,與實例變量需要通過對象來訪問相似
// 創建inner對象
inner.innerMethod();
// TODO Auto-generated method stub
}
}
運行結果:
內部類中 String =Hello!
外部類中的x =100
x is101
二、靜態內部類
-
與類的其它成員相似,可以用static修飾內部類,這樣的類稱爲靜態內部類。靜態內部類與靜態內部方法相似,只能訪問外部類的static成員,不能直接訪問外部類的實例變量與實例方法,只有通過對象引用才能訪問。
-
由於static內部類不具有任何對外部類實例的引用,因此static內部類中不能使用this關鍵字來訪問外部類中的實例成員,但是可以訪問外部類中的static成員。這與一般類的static方法相同。
具體代碼:
package com.m.ou;
public class MyOuter {
public static int x=100;
public static class MyInner{
private String y="Hello!";
public void innerMethod(){
System.out.println("x="+x);
System.out.println("y="+y);
}
}
/**
* @param args
*/
public static void main(String[] args) {
MyOuter.MyInner si=new MyOuter.MyInner();//靜態內部類不通過外部實例就可以創建對象;與類變量可以通過類名訪問相似
si.innerMethod();
// TODO Auto-generated method stub
}
}
運行結果:
x=100
y=Hello!
三、局部內部類
在方法體或語句塊(包括方法、構造方法、局部塊或靜態初始化塊)內部定義的類成爲局部內部類。局部內部類不能加任何訪問修飾符,因爲它只對局部塊有效。
- 局部內部類只在方法體中有效,就想定義的局部變量一樣,在定義的方法體外不能創建局部內部類的對象
- 在方法內部定義類時,應注意以下問題:
- 方法定義局部內部類同方法定義局部變量一樣,不能使用private、protected、public等訪問修飾說明符修飾,也不能使用static修飾,但可以使用final和abstract修飾。
- 方法中的內部類可以訪問外部類成員。對於方法的參數和局部變量,必須有final修飾纔可以訪問。
- static方法中定義的內部類可以訪問外部類定義的static成員。
示例代碼:
public class Jubu {
private int size=5,y=7;
public Object makeInner(int localVar){
final int finalLocalVar=localVar;
//創建內部類,該類只在makeInner()方法有效,就像局部變量一樣。在方法體外部不能創建MyInner類的對象
class MyInner{
int y=4;
public String toString(){
return "OuterSize:"+size+
"\nfinalLocalVar"+" "+"this.y="+this.y;
}
}
return new MyInner();
}
}
class Main{ /**
* @param args
*/
public static void main(String[] args) {
Object obj=new Jubu().makeInner(47);//創建Jubu對象obj,並調用它的makeInner()方法,該方法返回一個
//該方法返回一個MyInner類型的的對象obj,然後調用其同toString方法。
System.out.println(obj.toString());
// TODO Auto-generated method stub
}
}
運行結果:
OuterSize:5
finalLocalVar this.y=4
四、匿名內部類
定義類的最終目的是創建一個類的實例,但是如果某個類的實例只是用一次,則可以將類的定義與類的創建,放到與一起完成,或者說在定義類的同時就創建一個類。以這種方法定義的沒有名字的類稱爲匿名內部類。
聲明和構造匿名內部類的一般格式如下:
new ClassOrInterfaceName(){
/*類體*/ }
- 匿名內部類可以繼承一個類或實現一個接口,這裏的ClassOrInterfaceName是匿名內部類所繼承的類名或實現的接口名。但匿名內部類不能同時實現一個接口和繼承一個類,也不能實現多個接口。如果實現了一個接口,該類是Object類的直接子類,匿名類繼承一個類或實現一個接口,不需要extends和implements關鍵字。
- 由於匿名內部類沒有名稱,所以類體中不能定義構造方法,由於不知道類名也不能使用關鍵字來創建該類的實例。實際上匿名內部類的定義、構造、和第一次使用都發生在同樣一個地方。此外,上式是一個表達式,返回的是一個對象的引用,所以可以直接使用或將其複製給一個對象變量。例:
TypeName obj=new Name(){
/*此處爲類體*/
}
同樣,也可以將構造的對象作爲調用的參數。例:
someMethod(new Name(){
/*此處爲類體*/ });
示例代碼:
public class NiMing {
private int size=5;
public Object makeInner(int localVar){
final int finalLocalVar=localVar;
return new Object(){
//使用匿名內部類
public String toString(){
return "OuterSize="+size+"\nfinalLocalVar="+finalLocalVar;
}
};
}
/**
* @param args
*/
public static void main(String args[])
{
Object obj=new NiMing().makeInner(47);
System.out.println(obj.toString());
}
}
運行結果
OuterSize=5
finalLocalVar=47
更多內容,敬請關注公衆號【魯班AD】