1. 程式人生 > >Java中的內部類、匿名類、匿名內部類

Java中的內部類、匿名類、匿名內部類

內部類

Java中在一個類的內部定義的類叫做內部類(inner class)。建立一個內部類時,其物件就擁有了與外部類物件之間的關係。這種通過this來引用形成的,是內部類物件可以隨意訪問外部類中的所有成員變數!(因為被private修飾的成員變數和成員方法僅能被該類所使用,內部類中可以使用外部類的所有成員變數、成員方法)
Java程式中只能有一個public修飾的類且該類名是Java檔名的類,同時該Java程式中可以有多個類,但不能寫public(只能寫class)。
內部類的定義格式:

public class <檔名> {
	class <內部類名稱> {
		<內部類的成員變數和成員方法>;
	}
}

建立內部類物件時,必須通過外部類的例項來實現。(以Outer和Inner為例)

public class Outer {
	class Inner {
		<內部類成員變數和成員方法>;
	}
}

先建立外部類Outer類的例項,才能建立內部類Inner類的例項

Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();

等價於

Outer.Inner inner = new Outer().new Inner();

使用<引用形式是外部類物件名>.this來引用內部類物件的外部類的物件的所有成員變數和成員方法。(這裡僅僅只能在內部類中引用外部類通過這種方式引用外部類的成員和方法)
外部類物件和內部類物件之間是一對多關係,一個內部類物件只會引用一個外部類例項,而一個外部類物件可以對應多個內部類物件。在外部類中不能直接訪問內部類成員,必須通過內部類的例項訪問。
內部類中不能有被static修飾的任何成員變數和成員方法(被static修飾的成員變數和成員方法隨著類的載入而載入,此時內部類還不能在堆空間產生例項)。
實力內部類與外部類變數名相同時,通過<類名>.<成員變數名>

的方式來區分。Outer.a和Inner.a表示外部類、內部類的成員變數。

public class Outer {
    int num = 0;

    public void method() {
        System.out.println("num = " + num);
        System.out.println("this.num = " + this.num);
        System.out.println("Outer.this.num = " + Outer.this.num);
    }

    class Inner {
        int num = 1;

        public void method() {
            System.out.println("num = " + num);
            System.out.println("this.num = " + this.num);
            System.out.println("Outer.this.num = " + Outer.this.num);
        }
    }

    public static void main(String[] args) {
        Outer outer = new Outer();
        outer.method();
        System.out.println("------");
        Outer.Inner inner = outer.new Inner();
        inner.method();
    }
}

num = 0
this.num = 0
Outer.this.num = 0
------
num = 1
this.num = 1
Outer.this.num = 0

匿名類

在堆記憶體中定義,但未在棧記憶體開闢空間的物件。

new <類的構造方法>() {
};

可以直接在()後面.來呼叫相關成員變數或成員方法,不能被引用,一般只用一次,較多用於傳參或者返回值。當該類是抽象類時,必須實現該類所有的抽象方法。

new <抽象類的構造方法>() {
	@Override
	public <方法返回值> <抽象方法名> {
		<實現抽象方法>;
	}
};

匿名內部類

匿名內部類必須繼承一個父類或者實現一個介面,但是最多只能實現一個介面
匿名內部類由於沒有名字,因而無法定義構造方法,,編譯程式會自動生成該類的構造方法,並在其中自動呼叫其父類的構造方法。
在匿名內部類中可以定義例項變數、若干例項初始化程式碼塊和新的例項方法。Java虛擬機器首先會呼叫其父類的構造方法,然後按照例項變數和例項初始化程式碼塊定義的先後順序依次進行初始化。
被匿名內部類訪問的區域性變數必須是final變數,Java8以後自動使用final修飾匿名內部類的區域性變數。
匿名內部類可以直接訪問外部類所有成員變數和成員方法,包括外部類中用private的成員變數和成員方法。()

public class AnonymousInner {
    public AnonymousInner(int i) {
        System.out.println("another constructor");
    }

    public AnonymousInner() {
        System.out.println("default constructor");
    }

    public void method() {
        System.out.println("from AnonymousInner");
    }
    public static void main(String[] args) {
        new AnonymousInner().method();
        int i = 1;
        AnonymousInner anonymousInner = new AnonymousInner(i) {// 定義了一個繼承於AnonymousInner類的匿名內部類,大括號內是這個匿名內部類的類體,定義時直接生成了該類的物件並返回的一個例項引用。
            {
                System.out.println("initialize constructor");
            }
            public void method() {
                System.out.println("from anonymous" + i);
            }
        };
        anonymousInner.method();
    }
}

匿名內部類的{}中定義了例項變數、初始化程式碼塊和例項的方法(僅該例項物件可用,其他類根據自己的定義而使用)本例中增加了對其內部類類體的引用。便於未來使用該匿名內部類。
輸出結果如下

default constructor
from AnonymousInner
another constructor
initialize constructor
from anonymous1