一. 內部類簡介
在Java中,可以將一個類定義在另一個類裏面或者一個方法裏面,這樣的類稱爲內部類。《Thinking in Java》裏面講到:“使用內部類最吸引人的原因是:每個內部類都能獨立地繼承一個(接口的)實現,所以無論外圍類是否已經繼承了某個(接口的)實現,對於內部類都沒有影響”。使用內部類最大的優點是它能夠非常好的解決多重繼承的問題。
內部類有如下特性:
①內部類可以用多個實例,每個實例都有自己的狀態信息,並且與其他外圍對象的信息香菇獨立。
②在單個外圍類中,可以讓多個內部類以不同的方式實現同一個接口,或者繼承同一個類。
③創建內部類對象的時刻並不依賴於外圍類對象的創建。
④內部類並沒有令人迷惑的“is-a”關係,它就是一個獨立的實體。
⑤內部類提供了更好的封裝,除了該外圍類,其他類都不能訪問。
二. 內部類詳情
廣泛意義上的內部類一般來說包括這四種:成員內部類、局部內部類、匿名內部類和靜態內部類。
1. 成員內部類
成員內部類是最普通的內部類,它的定義爲位於另一個類的內部,形如下面的形式:
public class Circle {
private double radius = 0;
public Circle(double radius) {
this.radius = radius;
}
class Draw { //內部類
public void drawSahpe() {
System.out.println("draw shape");
}
}
}
類Draw像是類Circle的一個成員,Circle稱爲外部類。
成員內部類可以無條件訪問外部類的所有成員屬性和成員方法(包括private成員和靜態成員):
public class Circle {
private double radius = 0;
public static int count = 1;
public Circle(double radius) {
this.radius = radius;
}
class Draw { //內部類
public void drawSahpe() {
System.out.println(radius); //外部類的private成員
System.out.println(count); //外部類的靜態成員
}
}
}
不過要注意的是,當成員內部類擁有和外部類同名的成員變量或者方法時,會發生隱藏現象,即默認情況下訪問的是成員內部類的成員。如果要訪問外部類的同名成員,需要以下面的形式進行訪問:
外部類.this.成員變量
外部類.this.成員方法
雖然成員內部類可以無條件地訪問外部類的成員,而外部類想訪問成員內部類的成員卻不是這麼隨心所欲了。在外部類中如果要訪問成員內部類的成員,必須先創建一個成員內部類的對象,再通過指向這個對象的引用來訪問:
public class Circle {
private double radius = 0;
public Circle(double radius) {
this.radius = radius;
getDrawInstance().drawSahpe(); //必須先創建成員內部類的對象,再進行訪問
}
private Draw getDrawInstance() {
return new Draw();
}
class Draw { //內部類
public void drawSahpe() {
System.out.println(radius); //外部類的private成員
}
}
}
成員內部類是依附外部類而存在的,也就是說,如果要創建成員內部類的對象,前提是必須存在一個外部類的對象。創建成員內部類對象的一般方式如下:
public class Test {
public static void main(String[] args) {
//第一種方式:
Outter outter = new Outter();
Outter.Inner inner = outter.new Inner(); //必須通過Outter對象來創建
//第二種方式:
Outter.Inner inner1 = outter.getInnerInstance();
}
}
public class Outter {
private Inner inner = null;
public Outter() {
}
public Inner getInnerInstance() {
if(inner == null)
inner = new Inner();
return inner;
}
class Inner {
public Inner() {
}
}
}
內部類可以擁有private訪問權限、protected訪問權限、public訪問權限及包訪問權限。比如上面的例子,如果成員內部類Inner用private修飾,則只能在外部類的內部訪問,如果用public修飾,則任何地方都能訪問;如果用protected修飾,則只能在同一個包下或者繼承外部類的情況下訪問;如果是默認訪問權限,則只能在同一個包下訪問。
2. 局部內部類
局部內部類是定義在一個方法或者一個作用域裏面的類,它和成員內部類的區別在於局部內部類的訪問僅限於方法內或者該作用域內。
class People{
public People() {
}
}
class Man{
public Man(){
}
public People getWoman(){
class Woman extends People{ //局部內部類
int age =0;
}
return new Woman();
}
}
注意,局部內部類就像是方法裏面的一個局部變量一樣,是不能有public、protected、private以及static修飾符的。
3. 匿名內部類
匿名內部類應該是平時我們編寫代碼時用得最多的,在編寫事件監聽的代碼時使用匿名內部類不但方便,而且使代碼更加容易維護。比如我們經常在Android中使用匿名內部類編寫事件監聽代碼:
button1.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
}
});
匿名內部類是唯一一種沒有構造器的類。正因爲其沒有構造器,所以匿名內部類的使用範圍非常有限,大部分匿名內部類用於接口回調。匿名內部類在編譯的時候由系統自動起名爲Outter$1.class。一般來說,匿名內部類用於繼承其他類或是實現接口,並不需要增加額外的方法,只是對繼承方法的實現或是重寫。
4. 靜態內部類
靜態內部類也是定義在另一個類裏面的類,只不過在類的前面多了一個關鍵字static。靜態內部類是不需要依賴於外部類的,這點和類的靜態成員屬性有點類似,並且它不能使用外部類的非static成員變量或者方法,這點很好理解,因爲在沒有外部類的對象的情況下,可以創建靜態內部類的對象,如果允許訪問外部類的非static成員就會產生矛盾,因爲外部類的非static成員必須依附於具體的對象。
public class Test {
public static void main(String[] args) {
Outter.Inner inner = new Outter.Inner();
}
}
class Outter {
public Outter() {
}
static class Inner {
public Inner() {
}
}
}