Java內部類初探

2022-09-23 06:01:19

Java內部類初探

之前對內部類的概念不太清晰,在此對內部類與外部類之間的關係以及它們之間的呼叫方式進行一個總結。

Java內部類一般可以分為以下三種:

  • 成員內部類
  • 靜態內部類
  • 匿名內部類

一、成員內部類

  • 內部類的建立:成員內部類的建立需要依賴於外部類物件,沒有建立外部類範例之前無法建立成員內部類物件

    若在main函數中直接建立成員內部類則會報錯:

    MemberInner memberInner = new MemberInner();
    
  • 私有屬性存取:成員內部類可直接存取外部類非靜態私有屬性,外部類存取內部類私有屬性則需要通過內部類的物件來存取

    memberInnerTest()方法中,可以直接存取外部類中的私有test欄位,若內部類中有與外部類同名欄位,呼叫外部類需要使用如下方法:

    OuterTest.this.test
    
  • 建立內部類:

    • 在外部類內部建立內部類物件:使用new關鍵字建立內部類物件

      private void createMemberInner(){
          MemberInner memberInner = new MemberInner();
          memberInner.memberInnerTest();
      }
      
    • 在外部類外部建立內部類物件:需要先建立外部類物件,再通過外部類建立內部類

      OuterTest outerTest = new OuterTest();
      MemberInner memberInner = outerTest.new MemberInner();
      

      若不需要使用外部類,可以使用如下方式建立內部類

      MemberInner memberInner = new OuterTest().new MemberInner();
      

      使用該方法建立內部類需要注意:若外部類中有多個內部類,這種方法會new出多個外部類物件,各個類物件都是獨立的,因此外部類的成員變數並不會在內部類中共用。

      如下程式碼中,由於new出了兩個OuterVar類,所以InnerOneInnerTwo類輸出的成員變數var均為0。若想InnerOneInnerTwo類共用成員變數var,則需用如下方式建立:

        OuterVar outerVar = new OuterVar();
        InnerOne innerOne = outerVar.new InnerOne();
        InnerTwo innerTwo = outerVar.new InnerTwo();
      
      public class OuterVar {
      private int var = 0;
      
      class InnerOne{
        private void innerOnePrint(){
            System.out.println("innerOnePrint:"+var);
            var+=1;
        }
      }
      
      class InnerTwo{
        private void innerTwoPrint(){
            System.out.println("innerTwoPrint:"+var);
        }
      }
      
      public static void main(String[] args) {
        InnerOne innerOne = new OuterVar().new InnerOne();
        InnerTwo innerTwo = new OuterVar().new InnerTwo();
      
        innerOne.innerOnePrint();
        innerTwo.innerTwoPrint();
      }
      }
      /* 結果
      innerOnePrint:0
      innerTwoPrint:0
      */
      
/*1、成員內部類
  2、靜態內部類
  3、匿名內部類
*/
public class OuterTest {
    /*
    1、成員內部類
     */
    private String test = "OuterTest";

    private void createMemberInner(){
        MemberInner memberInner = new MemberInner();
        memberInner.memberInnerTest();
    }

    class MemberInner{
        private String test = "MemberInnerTest";

        public void memberInnerTest(){
            System.out.println("MemberInner");
            System.out.println(test);
            System.out.println(OuterTest.this.test);

        }
    }

    public static void main(String[] args) {
        // 成員內部類
        OuterTest outerTest = new OuterTest();
        MemberInner memberInner = outerTest.new MemberInner();
//        MemberInner memberInner = new OuterTest().new MemberInner();
        
        memberInner.memberInnerTest();
    }
}


/* 結果
   MemberInner
   MemberInnerTest
   OuterTest */

二、靜態內部類

靜態內部類定義在外部類的內部,使用static關鍵字修飾,靜態內部類不需要外部類物件產生就能使用,不能存取外部類的成員域,但能存取靜態域。

  • 私有屬性存取:靜態內部類不可直接存取外部類的非靜態屬性

  • 建立內部類:

    • 在外部類內部建立內部類物件:使用new關鍵字建立內部類物件

      private void createStaticInner(){
          StaticInner staticInner = new StaticInner();
          staticInner.staticInnerTest();
      }
      
    • 在外部類外部建立內部類物件:可以不建立外部類物件,直接建立內部類物件

      StaticInner staticInner = new StaticInner();
      
public class OuterTest {
    /*
      2、靜態內部類
     */
    private String test = "OuterTest";

    private void createStaticInner(){
        StaticInner staticInner = new StaticInner();
        staticInner.staticInnerTest();
    }


    static class StaticInner{
        private String test = "StaticInnerTest";

        public void staticInnerTest(){
            System.out.println("StaticInner");
            System.out.println(test);
        }
    }

    public static void main(String[] args) {
        // 靜態內部類
        StaticInner staticInner = new StaticInner();
        staticInner.staticInnerTest();
    }
}

/* 結果
   StaticInner
   StaticInnerTest */

三、匿名內部類

使用匿名內部類的前提條件:必須繼承一個父類別或實現一個介面。 有以下一些特點:

  • 由於匿名內部類是沒有類名,所以匿名內部類不能有構造方法
  • 匿名內部類不能定義任何靜態成員、方法和類
//匿名內部類
interface Father{
    public abstract void talk();

    public abstract void eat();
}
public class Test {
    public static void main(String[] args) {
        //匿名內部類
        Father father = new Father() {
            @Override
            public void talk() {
                System.out.println("I'm Father");
            }

            @Override
            public void eat() {
                System.out.println("I'm eating");
            }
        };
        father.talk();
        father.eat();
    }
}

/* 結果
   I'm Father
   I'm eating */