首頁 > 軟體

java的內部類和外部類用法講解

2021-12-08 19:01:29

一、為何使用內部類

  • 內部類提供了更好的封裝,只有外部類能存取內部類
  • 內部類可以獨立繼承一個介面,不受外部類是否繼承介面影響
  • 內部類中的屬性和方法即使是外部類也不能直接存取,相反內部類可以直接存取外部類的屬性和方法,即使private
  • 利於回撥函數的編寫

一個內部類的例子:

public class OuterClass {
    private String outerName;
    private int outerAge;
    public class InnerClass{
        private String innerName;
        private int innerAge;
    }
}

二、內部類與外部類的聯絡

2.1 內部類是一個相對獨立的實體,與外部類不是is-a關係

內部類是一個編譯時概念,編譯後外部類及其內部類會生成兩個獨立的class檔案: OuterClass.class和OuterClass$InnerClass.class,我用javac編譯器對上面的OuterClass進行編譯:

 D:>javac OuterClass.class

編譯後的結果:

2.2 內部類可以直接存取外部類的元素,但是外部類不可以直接存取內部類的元素

public class OuterClass {

    private String outerName;
    private int outerAge;

    public class InnerClass{
        private int innerName;
        InnerClass(){
            //內部類可以存取外部類的元素
            outerName="I am outer class";
            outerAge=23;
        }
        public void display(){
            System.out.println(outerName+" and my age is "+outerAge);
        }
    }
    public static void main(String[] args) {
        OuterClass outerClass = new OuterClass();
        OuterClass.InnerClass innerClass = outerClass.new InnerClass();
        innerClass.display();
    }
}

在上面例子中我們可以看到,內部類可以直接存取外部類屬性,儘管外部類屬性是用private修飾的。這是因為在建立外部類時,內部類會自動捕獲一個外部類的參照,所以內部類存取外部類元素,實際上是通過他所持有外部類參照存取的。在java中,我們可以通過OuterClass.this來獲得外部類的參照,請看下面例子:

public class OuterClass {
    public void display(){
        System.out.println("this is OuterClass...");
    }
    public class InnerClass{
        //獲取外部類的參照
        public OuterClass getOuterClass(){
            return OuterClass.this;
        }
        public void innerDisplay(){
            //內部類也可以通過外部類的參照存取外部元素
            getOuterClass().display();
        }
    }
    public static void main(String[] args) {
        OuterClass outerClass = new OuterClass();
        OuterClass.InnerClass innerClass = outerClass.new InnerClass();
        innerClass.innerDisplay();
    }
}

2.3 外部類可以通過內部類參照間接存取內部類元素

public class OuterClass {
    public void display(){
        //外部類存取內部類元素,需要通過內部類參照存取
        InnerClass innerClass=new InnerClass();
        innerClass.innerDisplay();
    }
    public class InnerClass{
        public void innerDisplay(){
            System.out.println("I am inner class");
        }
    }
    public static void main(String[] args) {
        OuterClass outerClass=new OuterClass();
        outerClass.display();
    }
}

三、建立內部類

3.1 在外部類外面(或外部類main方法)建立內部了物件

其實上面2.2例子中我們已經看到了如何建立內部類。如果要建立一個內部類物件,必須利用outerClass.new來建立:

1 OuterClass outerClass = new OuterClass();

2 OuterClass.InnerClass innerClass = outerClass.new InnerClass();  

其實我們還可以一步到位: OuterClass.InnerClass innerClass=new OuterClass().new InnerClass(); 

內部類建立方法範例:

public static void main(String[] args) {
    //先建立外部類物件,再建立內部類物件
    OuterClass outerClass = new OuterClass();
    OuterClass.InnerClass innerClass1 = outerClass.new InnerClass();
    innerClass1.innerDisplay();
    //一步到位建立
    OuterClass.InnerClass innerClass2=new OuterClass().new InnerClass();
    innerClass2.innerDisplay();
}

3.2 在外部類裡面建立內部類

正如2.3程式碼中display()方法那樣,在外部類裡面建立內部類,就像建立普通物件一樣直接建立:

InnerClass innerClass=new InnerClass()

四、內部類的種類:

在Java中內部類主要分為成員內部類、方法內部類、匿名內部類、靜態內部類。

4.1 成員內部類

成員內部類也是最普通的內部類,它是外部類的一個成員,所以他是可以無限制的存取外圍類的所有成員屬性和方法,儘管是private的,但是外圍類要存取內部類的成員屬性和方法則需要通過內部類範例來存取。

在成員內部類中要注意兩點:

  • 成員內部類中不能存在任何static的變數和方法
  • 成員內部類是依附於外圍類的,所以只有先建立了外圍類才能夠建立內部類

4.2 方法內部類

方法內部類定義在外部類的方法中,區域性內部類和成員內部類基本一致,只是它們的作用域不同,方法內部類只能在該方法中被使用,出了該方法就會失效。 對於這個類的使用主要是應用與解決比較複雜的問題,想建立一個類來輔助我們的解決方案,到那時又不希望這個類是公共可用的,所以就產生了區域性內部類。

4.3 匿名內部類

匿名內部類其實就是一個沒有名字的方法內部類,所以它符合方法內部類的所有約束,初次之外,還有一些地方需要注意:

  1. 匿名內部類是沒有存取修飾符的。
  2. 匿名內部類必須繼承一個抽象類或者實現一個介面
  3. 匿名內部類中不能存在任何靜態成員或方法
  4. 匿名內部類是沒有構造方法的,因為它沒有類名。

一般使用匿名內部類的場景是,要繼承或實現的介面只有一個抽象方法,比如新增一個監聽器:

public class Button {
    public void click(){
        //匿名內部類,實現的是ActionListener介面
        new ActionListener(){
            public void onAction(){
                System.out.println("click action...");
            }
        }.onAction();
    }
    //匿名內部類必須繼承或實現一個已有的介面
    public interface ActionListener{
        public void onAction();
    }

    public static void main(String[] args) {
        Button button=new Button();
        button.click();
    }
}

4.4 靜態內部類

關鍵字static可以修飾成員變數、方法、程式碼塊,其實它還可以修飾內部類,使用static修飾的內部類我們稱之為靜態內部類。靜態內部類與非靜態內部類之間存在一個最大的區別,我們知道非靜態內部類在編譯完成之後會隱含地儲存著一個參照,該參照是指向建立它的外圍內,但是靜態內部類卻沒有。沒有這個參照就意味著:

  • 靜態內部類的建立是不需要依賴於外圍類,可以直接建立
  • 靜態內部類不可以使用任何外圍類的非static成員變數和方法,而內部類則都可以
public class OuterClass {
    private static String outerName;
    public  int age;

    static class InnerClass1{
        /* 在靜態內部類中可以存在靜態成員 */
        public static String _innerName = "static variable";
        public void display(){
            /*
             * 靜態內部類只能存取外部類的靜態成員變數和方法
             * 不能存取外部類的非靜態成員變數和方法
             */
            System.out.println("OutClass name :" + outerName);
        }
    }
    class InnerClass2{
        /* 非靜態內部類中不能存在靜態成員 */
        public String _innerName = "no static variable";
        /* 非靜態內部類中可以呼叫外部類的任何成員,不管是靜態的還是非靜態的 */
        public void display(){
            System.out.println("OuterClass name:" + outerName);
            System.out.println("OuterClass age:" + age);
        }
    }
    public void display(){
        /* 外部類能直接存取靜態內部類靜態元素 */
        System.out.println(InnerClass1._innerName);
        /* 靜態內部類可以直接建立範例不需要依賴於外部類 */
        new InnerClass1().display();
        /* 非靜態內部的建立需要依賴於外部類 */
        OuterClass.InnerClass2 inner2 = new OuterClass().new InnerClass2();
        /* 非靜態內部類的成員需要使用非靜態內部類的範例存取 */
        System.out.println(inner2._innerName);
        inner2.display();
    }

    public static void main(String[] args) {
        OuterClass outer = new OuterClass();
        outer.display();
    }
}

到此這篇關於java的內部類和外部類用法講解的文章就介紹到這了。希望對大家的學習有所幫助,也希望大家多多支援it145.com。


IT145.com E-mail:sddin#qq.com