Java進階07 巢狀類

ii_chengzi發表於2019-11-21

到現在為止,我們都是在Java檔案中直接定義類。這樣的類出現在包(package)的級別上。Java允許類的巢狀定義。

這裡將講解如何在一個類中巢狀定義另一個類。

 巢狀

內部類

Java允許我們在類的內部定義一個類。如果這個類是沒有static修飾符,那麼這樣一個巢狀在內部的類稱為 內部類(inner class)。

內部類被認為是外部物件的一個 成員。在定義內部類時,我們同樣有 訪問許可權控制(public, private, protected)。

 

在使用內部類時,我們要先建立外部物件。由於內部類是外部物件的一個成員,我們可以在物件的內部自由使用內部類:

public class Test
{    public static void main(String[] args)
    {
        Human me        = new Human("Vamei");
        me.drinkWater(0.3);
    }
}class Human
{    /**
     * inner class     */
    private class Cup
    {        public void useCup(double w)
        {            this.water = this.water - w;
        }        public double getWater()
        {            return this.water;
        }        private double water = 1.0;
    }    /**
     * constructor     */
    public Human(String n)
    {        this.myCup = new Cup();        this.name  = n;
    }    public void drinkWater(double w)
    {
        myCup.useCup(w);
        System.out.println(myCup.getWater());
    }    private Cup myCup;    private String name;
}

上面的例子中,Cup類為內部類。該內部類有private的訪問許可權,因此只能在Human內部使用。這樣,Cup類就成為一個被Human類 專用的類。

 

如果我們使用其他訪問許可權,內部類也能從外部訪問,比如:

public class Test
{    public static void main(String[] args)
    {
        Human me        = new Human("Vamei");
        me.drinkWater(0.3);
        Human.Cup soloCup = me.new Cup(); // be careful here
    }
}class Human
{    /**
     * inner class     */                                                                                                                                                             
    class Cup
    {        public void useCup(double w)
        {            this.water = this.water - w;
        }        public double getWater()
        {            return this.water;
        }        private double water = 1.0;
    }    /**
     * constructor     */
    public Human(String n)
    {        this.myCup = new Cup();        this.name  = n;
    }    public void drinkWater(double w)
    {
        myCup.useCup(w);
        System.out.println(myCup.getWater());
    }    private Cup myCup;    private String name;
}

這裡,內部類為預設訪問許可權(包訪問許可權)。我們可以在Test類中訪問Human的內部類Cup,並使用該內部類建立物件。注意我們建立時如何說明型別以及使用new:

Human.Cup soloCup = me.new Cup();

我們在建立內部類物件時,必須基於一個外部類物件(me),並透過該外部類物件來建立Cup物件(me.new)。我將在下一節講述其中的含義。

 

閉包

可以看到,我們直接建立內部類物件時,必須是基於一個外部類物件。也就是說,內部類物件必須 依附於某個外部類物件。

 

內部物件與外部物件

與此同時, 內部類物件 可以訪問它所依附的外部類物件的成員(即使是private的成員)。從另一個角度來說,內部類物件附帶有建立時的環境資訊,也就是其他語言中的 閉包(closure)特性。可參考 Python閉包

我們看下面的例子:

public class Test
{    public static void main(String[] args)
    {
        Human me        = new Human("Vamei");
        Human him       = new Human("Jerry");
        Human.Cup myFirstCup  = me.new Cup();
        Human.Cup mySecondCup = me.new Cup();
        Human.Cup hisCup      = him.new Cup();
        System.out.println(myFirstCup.whosCup());
        System.out.println(mySecondCup.whosCup());
        System.out.println(hisCup.whosCup());
    }
}class Human
{    /**
     * inner class     */
    class Cup
    {        public String whosCup()
        {            return name;  // access outer field        }
    }    /**
     * constructor     */
    public Human(String n)
    {        this.name = n;
    }    public void changeName(String n)
    {        this.name = n;
    }    private String name;
}

執行結果:

Vamei
Vamei
Jerry

 

在上面的例子中,我們透過內部類物件訪問外部類物件的name成員。當我們基於不同的外部物件建立內部類物件時,所獲得的環境資訊也將隨之變化。

 

巢狀static類 

我們可以在類的內部定義 static類。這樣的類稱為 巢狀static類(nested static class)。

我們可以直接建立巢狀static類的物件,而不需要依附於外部類的某個物件。相應的,巢狀static類也無法呼叫外部物件的方法,也無法讀取或修改外部物件的資料。從效果上看,巢狀static類擴充了類的名稱空間(name space),比如下面的 Human.Mongolian:

public class Test
{    public static void main(String[] args)
    {
        Human.Mongolian him = new Human.Mongolian();
        him.Shout();
    }
}class Human
{    /**
     * nested class     */
    static class Mongolian
    {        public void Shout()
        {
            System.out.println("Oh...Ho...");
        }
    }
}

在定義巢狀static類時,我們同樣可以有不同的 訪問許可權修飾符。

 

總結

巢狀類允許我們更好的組織類

內部類實現了閉包

 

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31543790/viewspace-2665092/,如需轉載,請註明出處,否則將追究法律責任。

相關文章