OnJava8筆記5 -- 內(nèi)部類

內(nèi)部類

一個(gè)定義在另一個(gè)類中的類,叫作內(nèi)部類。

創(chuàng)建內(nèi)部類

public class Parcel {
    class Contents {
        private int i = 11;

        public int value() { return i; }
    }
}
  • 在Parcel之外的類中想要?jiǎng)?chuàng)建Contents對(duì)象,需要 Parcel.Contents ( OuterClassName.InnerClassName )

  • 內(nèi)部類自動(dòng)擁有對(duì)其外圍類所有成員和方法的訪問權(quán),即使是 private 的也可以。這是因?yàn)楫?dāng)內(nèi)部類對(duì)象被創(chuàng)建時(shí),一個(gè)外部類對(duì)象的引用被傳遞給這個(gè)內(nèi)部類對(duì)象了。

  • 普通內(nèi)部類不能有 static 字段和方法

內(nèi)部類中的 .this 和 .new

.this

  • 在內(nèi)部類中, *OuterClassName.this *(DotThis.this) 代表的是外部類對(duì)象的引用,單純的 this 就是內(nèi)部類對(duì)象的引用

.new

  • 外部類對(duì)象.new 用于創(chuàng)建內(nèi)部類對(duì)象

    public class DotNew {
        public class Inner {}
        public static void main(String[] args) {
            DotNew dn = new DotNew();
            DotNew.Inner dni = dn.new Inner();
        }
    }
    

方法和作用域中的內(nèi)部類

public class Parcel6 {
    private void internalTracking(boolean b) {
        if(b) {
            class TrackingSlip {
                private String id;
                TrackingSlip(String s) {
                    id = s;
                }
                String getSlip() { return id; }
            }
            TrackingSlip ts = new TrackingSlip("slip");
            String s = ts.getSlip();
        }
        // Can't use it here! Out of scope:
        //- TrackingSlip ts = new TrackingSlip("x");
    }
}

內(nèi)部類只能在自己的作用域中能被使用

  • 方法和作用域中的內(nèi)部類使用的外部變量必須是final的

匿名內(nèi)部類

public interface Contents {
    int value();
}
public class Parcel7 {
    public Contents contents() {
        return new Contents() { // Insert class definition
            private int i = 11;

            @Override
            public int value() { return i; }
        }; // Semicolon required
    }

    public static void main(String[] args) {
        Parcel7 p = new Parcel7();
        Contents c = p.contents();
    }
}

在創(chuàng)建 Contents 對(duì)象代碼之后插入一個(gè)類的聲明,這個(gè)插入的類就是匿名類(沒有具體名字)

  • 這里可以看成創(chuàng)建了一個(gè)繼承自 Contents 的匿名類對(duì)象,然后通過前面的 new 表達(dá)式將匿名類對(duì)象向上轉(zhuǎn)型成 Contents 對(duì)象
  • 匿名內(nèi)部類中使用的外部變量必須是final 的
  • 匿名內(nèi)部類,因?yàn)槭悄涿?,不能顯式聲明構(gòu)造函數(shù)

匿名內(nèi)部類中的參數(shù)初始化

public class Parcel9 {
    // Argument must be final or "effectively final"
    // to use within the anonymous inner class:
    public Destination destination(final String dest) {
        return new Destination() {
            private String label = dest;
            @Override
            public String readLabel() { return label; }
        };
    }
    public static void main(String[] args) {
        Parcel9 p = new Parcel9();
        Destination d = p.destination("Tasmania");
    }
}

可以看到第6行用到的外部變量是final的(jdk8之后不用明確寫final了,但還是不能被改變)
為什么必須是final的? 參考知乎 胖君 的回答:https://www.zhihu.com/question/21395848

嵌套類

static類型的內(nèi)部類叫做嵌套類。嵌套類對(duì)象沒有指向外部創(chuàng)建他的類的對(duì)象引用

  • 要?jiǎng)?chuàng)建嵌套類對(duì)象,不需要外部類對(duì)象
  • 不能從嵌套類的對(duì)象中訪問非靜態(tài)外部類的對(duì)象
  • 嵌套類可以包含 static 字段和方法
  • 接口中的內(nèi)部類自動(dòng)是 public 和 static 的

為什么要使用內(nèi)部類

  • 最重要的原因是可以間接實(shí)現(xiàn)類的多繼承

    我們知道java中的類只能單繼承,內(nèi)部類可以間接實(shí)現(xiàn)多繼承:

    public class Demo1 {
          public String name() {
              return "BWH_Steven";
          }
      }
      
      public class Demo2 {
          public String email() {
              return "xxx.@163.com";
          }
      }
      
      public class MyDemo {
      
          private class test1 extends Demo1 {
              public String name() {
                  return super.name();
              }
          }
      
          private class test2 extends Demo2  {
              public String email() {
                  return super.email();
              }
          }
      
          public String name() {
              return new test1().name();
          }
      
          public String email() {
              return new test2().email();
          }
      
          public static void main(String args[]) {
              MyDemo md = new MyDemo();
              System.out.println("我的姓名:" + md.name());
              System.out.println("我的郵箱:" + md.email());
          }
    }
    

    在MyDemo類中書寫了兩個(gè)內(nèi)部類,test1和test2 兩者分別繼承了Demo1和Demo2類,這樣MyDemo中就間接的實(shí)現(xiàn)了多繼承

  • 使用匿名內(nèi)部類實(shí)現(xiàn)回調(diào)功能(jdk8之后可以使用lambda表達(dá)式)
    當(dāng)有這么個(gè)需求,一個(gè)方法的參數(shù)是接口對(duì)象,因?yàn)榻涌诓荒苌蓪?duì)象,而單獨(dú)寫一個(gè)類來實(shí)現(xiàn)接口又太浪費(fèi)(因?yàn)檫@個(gè)方法可能只會(huì)被使用一次),這時(shí)匿名內(nèi)部類很容易實(shí)現(xiàn)這一需求

    interface Demo {
        void interfaceMethod();
    }
    
    public class NiMingInnerClass {
    
        public void test(Demo demo) {
            demo.interfaceMethod();
        }
    
        public static void main(String[] args) {
            NiMingInnerClass innerClass = new NiMingInnerClass();
            innerClass.test(new Demo() {
                @Override
                public void interfaceMethod() {
                    System.out.println("接口方法被調(diào)用了");
                }
            });
        }
    }
    
  • 父類和接口中存在同名方法,而直接Override這個(gè)方法會(huì)導(dǎo)致只能保留一個(gè)方法,想要既保留繼承自父類的實(shí)現(xiàn),又保留接口中的方法,這時(shí)選擇內(nèi)部類很容易達(dá)到需求

    interface Demo2 {
        void test();
    }
    abstract class  SupClass {
        public void test() {
            System.out.println("SupClass test()");
        }
    
    }
    
    public class SameNameMethod extends SupClass {
        @Override
        public void test() {
            super.test();
            System.out.println("SameNameMethod test()");
        }
    
        private class InnerClass implements Demo2{
            @Override
            public void test() {
                System.out.println("Demo2 test()");
            }
    
    
        }
    
        public InnerClass getInner() {
            return new InnerClass();
        }
        public static void main(String[] args) {
            SameNameMethod test = new SameNameMethod();
            test.test();
            test.getInner().test();
        }
    }
    
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容