乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      [轉(zhuǎn)載]詳析內(nèi)部類

       iversion 2008-01-15

      [轉(zhuǎn)載]詳析內(nèi)部類

      本文主要參照網(wǎng)上的一些相關(guān)文章、以及thinking in java 第三版,對java里面的內(nèi)部類進行了一個較為詳細的總結(jié)
      內(nèi)部是指在一個外部的內(nèi)部再定一個。內(nèi)部外部的一個成,并且依附于外部而存在的。內(nèi)部態(tài),可用protectedprivate(而外部只能使用public和缺省的包訪問權(quán)限)。內(nèi)部類主要有以下幾類:內(nèi)部、局部內(nèi)部、靜態(tài)內(nèi)部、匿名內(nèi)部
      為什么需要內(nèi)部類?
      典型的情況是,內(nèi)部類繼承自某個類或?qū)崿F(xiàn)某個接口,內(nèi)部類的代碼操作創(chuàng)建其的外圍類的對象。所以你可以認為內(nèi)部類提供了某種進入其外圍類的窗口。使用內(nèi)部類最吸引人的原因是:
      每個內(nèi)部類都能獨立地繼承自一個(接口的)實現(xiàn),所以無論外圍類是否已經(jīng)繼承了某個(接口的)實現(xiàn),對于內(nèi)部類都沒有影響。如果沒有內(nèi)部類提供的可以繼承多個具體的或抽象的類的能力,一些設計與編程問題就很難解決。從這個角度看,內(nèi)部類使得多重繼承的解決方案變得完整。接口解決了部分問題,而內(nèi)部類有效地實現(xiàn)了“多重繼承”。
      A:成員內(nèi)部類
      外部的一個成存在,與外部的屬性、方法并列。
      publicclass Outer {
             privatestaticinti = 1;
             privateintj = 10;
             privateintk = 20;
             publicstaticvoidouter_f1() {
             }
             publicvoidouter_f2() {
             }
             // 內(nèi)部中,不能定態(tài)
             // 內(nèi)部中,可以訪問外部的所有成
             class Inner {
                    // static int inner_i = 100;//內(nèi)部中不允態(tài)變
                    intj = 100; // 內(nèi)部和外部量可以共存
                    intinner_i = 1;
                    void inner_f1() {
                           System.out.println(i);
                               //在內(nèi)部訪問內(nèi)部自己的量直接用量名
                           System.out.println(j);
                               //在內(nèi)部訪問內(nèi)部自己的量也可以用this.量名
                           System.out.println(this.j);
                               //在內(nèi)部訪問外部中與內(nèi)部同名的量用外部.this.量名
                           System.out.println(Outer.this.j);
                               //如果內(nèi)部中沒有與外部同名的量,可以直接用量名訪問外部類變
                           System.out.println(k);
                                                outer_f1();
                                                outer_f2();
                    }
             }
             //外部的非靜態(tài)方法訪問內(nèi)部
             publicvoidouter_f3() {
                    Inner inner = new Inner();
                    inner.inner_f1();
             }
             // 外部的靜態(tài)方法訪問內(nèi)部,與在外部外部訪問內(nèi)部
             publicstaticvoidouter_f4() {
                    //step1 建立外部類對
                    Outer out = new Outer();
                    //step2 根據(jù)外部類對象建立內(nèi)部類對
                    Inner inner = out.new Inner();
                    //step3 訪問內(nèi)部的方法
                    inner.inner_f1();
             }
             publicstaticvoid main(String[] args) {
                    //outer_f4();//該語句的結(jié)果和下面三條句的結(jié)果一
                    //如果要直接創(chuàng)建內(nèi)部象,不能想當然地認為只需加上外圍類Outer的名字,
                    //就可以按照通常的子生成內(nèi)部象,而是必使用此外圍類的一個象來
                    //創(chuàng)建其內(nèi)部的一個象:
                    //Outer.Inner outin = out.new Inner()
                    //因此,除非你已經(jīng)有了外圍類的一個象,否不可能生成內(nèi)部象。因
                    //內(nèi)部象會悄悄地接到創(chuàng)建它的外圍類象。如果你用的是靜態(tài)的內(nèi)部,
                    //那就不需要其外圍類對象的引用。
                    Outer out = new Outer();
                    Outer.Inner outin = out.new Inner();
                    outin.inner_f1();
             }
      }

      注意:內(nèi)部是一個編譯時的概念,一旦編譯成功,就會成完全不同的兩。于一個名outer的外部和其內(nèi)部定的名inner的內(nèi)部。編譯完成后出現(xiàn)outer.classouter$inner.class。
      B:局部內(nèi)部類
      在方法中定的內(nèi)部局部內(nèi)部。與局部似,局部內(nèi)部類不能有訪問說明符,因為它不是外圍類的一部分,但是它可以訪問當前代碼塊內(nèi)的常量,和此外圍類所有的成員。
      publicclass Outer {
             privateints = 100;
             privateintout_i = 1;
             publicvoid f(finalint k) {
                    finalint s = 200;
                    int i = 1;
                    finalint j = 10;
                   
                       //在方法內(nèi)部
                    class Inner {
                           ints = 300;// 可以定與外部同名的
                           // static int m = 20;//不可以定態(tài)變
                           Inner(int k) {
                                  inner_f(k);
                           }
                           intinner_i = 100;
                           voidinner_f(int k) {
                               //如果內(nèi)部沒有與外部同名的量,在內(nèi)部中可以直接訪問外部
                                  System.out.println(out_i);
                               //可以訪問外部的局部(即方法內(nèi)的),但是量必final
                                  System.out.println(j);
                                  //System.out.println(i);
                               //如果內(nèi)部中有與外部同名的量,直接用量名訪問的是內(nèi)部
                                  System.out.println(s);
                               //this.量名訪問的也是內(nèi)部類變
                                  System.out.println(this.s);
                               //用外部.this.內(nèi)部類變量名訪問的是外部類變
                                  System.out.println(Outer.this.s);
                           }
                    }
                    new Inner(k);
             }
             publicstaticvoid main(String[] args) {
                    // 訪問局部內(nèi)部先有外部類對
                    Outer out = new Outer();
                    out.f(3);
             }
      }
      C:靜態(tài)內(nèi)部類(嵌套類)(注意:前兩內(nèi)部似,所以可以照參考量)
      如果你不需要內(nèi)部類對象與其外圍類對象之間有聯(lián)系,那你可以將內(nèi)部類聲明為static。這通常稱為嵌套類(nested class)。想要理解static應用于內(nèi)部類時的含義,你就必須記住,普通的內(nèi)部類對象隱含地保存了一個引用,指向創(chuàng)建它的外圍類對象。然而,當內(nèi)部類是static的時,就不是這樣了。嵌套類意味著:
      1. 要創(chuàng)建嵌套類的對象,并不需要其外圍類的對象。
      2. 不能從嵌套類的對象中訪問非靜態(tài)的外圍類對象。
      publicclass Outer {
             privatestaticinti = 1;
             privateintj = 10;
             publicstaticvoidouter_f1() {
             }
             publicvoidouter_f2() {
             }
             // 態(tài)內(nèi)部可以用public,protected,private
             // 態(tài)內(nèi)部中可以定態(tài)或者非靜態(tài)的成
             staticclass Inner {
                    staticintinner_i = 100;
                    intinner_j = 200;
                    staticvoidinner_f1() {
                            //態(tài)內(nèi)部只能訪問外部的靜態(tài)(包括靜態(tài)變量和靜態(tài)方法)
                           System.out.println("Outer.i" + i);
                           outer_f1();
                    }
                    voidinner_f2() {
                           // 態(tài)內(nèi)部不能訪問外部的非靜態(tài)(包括非靜態(tài)變量和非靜態(tài)方法)
                           // System.out.println("Outer.i"+j);
                           // outer_f2();
                    }
             }
             publicvoidouter_f3() {
                    // 外部類訪問內(nèi)部的靜態(tài):內(nèi)部.態(tài)
                    System.out.println(Inner.inner_i);
                    Inner.inner_f1();
                    // 外部類訪問內(nèi)部的非靜態(tài):例化內(nèi)部即可
                    Inner inner = new Inner();
                    inner.inner_f2();
             }
             publicstaticvoid main(String[] args) {
                    newOuter().outer_f3();
             }
      }

      生成一個靜態(tài)內(nèi)部不需要外部是靜態(tài)內(nèi)部和成內(nèi)部的區(qū)。靜態(tài)內(nèi)部象可以直接生成:Outer.Inner in = new Outer.Inner();而不需要通生成外部類對象來生成。這樣實際上使靜態(tài)內(nèi)部了一個頂級類(正常情況下,你不能在接口內(nèi)部放置任何代碼,但嵌套類可以作為接口的一部分,因為它是static 的。只是將嵌套類置于接口的命名空間內(nèi),這并不違反接口的規(guī)則)
      D:匿名內(nèi)部類(from thinking in java 3th)
      簡單地說:匿名內(nèi)部類就是沒有名字的內(nèi)部類。什么情況下需要使用匿名內(nèi)部類?如果滿足下面的一些條件,使用匿名內(nèi)部類是比較合適的:
        ·只用到類的一個實例。
        ·類在定義后馬上用到。
        ·類非常?。?/span>SUN推薦是在4行代碼以下)
        ·給類命名并不會導致你的代碼更容易被理解。
        在使用匿名內(nèi)部類時,要記住以下幾個原則:
        ·匿名內(nèi)部類不能有構(gòu)造方法。
        ·匿名內(nèi)部類不能定義任何靜態(tài)成員、方法和類。
        ·匿名內(nèi)部類不能是public,protected,private,static。
        ·只能創(chuàng)建匿名內(nèi)部類的一個實例。
      ·一個匿名內(nèi)部類一定是在new的后面,用其隱含實現(xiàn)一個接口或?qū)崿F(xiàn)一個類。
        ·因匿名內(nèi)部類為局部內(nèi)部類,所以局部內(nèi)部類的所有限制都對其生效。

      下面的例子看起來有點奇怪:
      //在方法中返回一個匿名內(nèi)部類
      public class Parcel6 {
              public Contents cont() {
                      return new Contents() {
                           private int i = 11;
                           public int value() {
                                  return i;
                           }
                    }; // 在這里需要一個分號
              }
              public static void main(String[] args) {
                      Parcel6 p = new Parcel6();
                      Contents c = p.cont();
              }
      }
      cont()方法將下面兩個動作合并在一起:返回值的生成,與表示這個返回值的類的定義!進一步說,這個類是匿名的,它沒有名字。更糟的是,看起來是你正要創(chuàng)建一個Contents對象:
      return new Contents()
      但是,在到達語句結(jié)束的分號之前,你卻說:“等一等,我想在這里插入一個類的定義”:
      return new Contents() {
      private int i = 11;
      public int value() { return i; }
      };
      這種奇怪的語法指的是:“創(chuàng)建一個繼承自Contents的匿名類的對象。”通過new 表達式返回的引用被自動向上轉(zhuǎn)型為對Contents的引用。匿名內(nèi)部類的語法是下面例子的簡略形式:
      class MyContents implements Contents {
      private int i = 11;
      public int value() { return i; }
          }
      return new MyContents();
      在這個匿名內(nèi)部類中,使用了缺省的構(gòu)造器來生成Contents。下面的代碼展示的是,如果你的基類需要一個有參數(shù)的構(gòu)造器,應該怎么辦:
      public class Parcel7 {
      public Wrapping wrap(int x) {
      // Base constructor call:
      return new Wrapping(x) { // Pass constructor argument.
      public int value() {
      return super.value() * 47;
                  }
      }; // Semicolon required
          }
      public static void main(String[] args) {
      Parcel7 p = new Parcel7();
      Wrapping w = p.wrap(10);
          }
      }
      只需簡單地傳遞合適的參數(shù)給基類的構(gòu)造器即可,這里是將x 傳進new Wrapping(x)。在匿名內(nèi)部類末尾的分號,并不是用來標記此內(nèi)部類結(jié)束(C++中是那樣)。實際上,它標記的是表達式的結(jié)束,只不過這個表達式正巧包含了內(nèi)部類罷了。因此,這與別的地方使用的分號是一致的。
      如果在匿名類中定義成員變量,你同樣能夠?qū)ζ鋱?zhí)行初始化操作:
      public class Parcel8 {
      // Argument must be final to use inside
      // anonymous inner class:
      public Destination dest(final String dest) {
      return new Destination() {
      private String label = dest;
      public String readLabel() { return label; }
      };
          }
      public static void main(String[] args) {
      Parcel8 p = new Parcel8();
      Destination d = p.dest("Tanzania");
          }
      }
      如果你有一個匿名內(nèi)部類,它要使用一個在它的外部定義的對象,編譯器會要求其參數(shù)引用是final 型的,就像dest()中的參數(shù)。如果你忘記了,會得到一個編譯期錯誤信息。如果只是簡單地給一個成員變量賦值,那么此例中的方法就可以了。但是,如果你想做一些類似構(gòu)造器的行為,該怎么辦呢?在匿名類中不可能有已命名的構(gòu)造器(因為它根本沒名字?。?,但通過實例初始化,你就能夠達到為匿名內(nèi)部類“制作”一個構(gòu)造器的效果。像這樣做:
      abstract class Base {
      public Base(int i) {
      System.out.println("Base constructor, i = " + i);
          }
      public abstract void f();
      }
      public class AnonymousConstructor {
      public static Base getBase(int i) {
      return new Base(i) {
                  {
      System.out.println("Inside instance initializer");
                  }
      public void f() {
      System.out.println("In anonymous f()");
                  }
      };
          }
      public static void main(String[] args) {
      Base base = getBase(47);
      base.f();
          }
      }
      在此例中,不要求變量i 一定是final 的。因為i 被傳遞給匿名類的基類的構(gòu)造器,它并不會在匿名類內(nèi)部被直接使用。下例是帶實例初始化的“parcel”形式。注意dest()的參數(shù)必須是final,因為它們是在匿名類內(nèi)被使用的。
      public class Parcel9 {
      public Destinationdest(final String dest, final float price) {
      return new Destination() {
      private int cost;
      // Instance initialization for each object:
                  {
      cost = Math.round(price);
      if(cost > 100)
      System.out.println("Over budget!");
                  }
      private String label = dest;
      public String readLabel() { return label; }
      };
          }
      public static void main(String[] args) {
      Parcel9 p = new Parcel9();
      Destination d = p.dest("Tanzania", 101.395F);
          }
      }
      在實例初始化的部分,你可以看到有一段代碼,那原本是不能作為成員變量初始化的一部分而執(zhí)行的(就是if 語句)。所以對于匿名類而言,實例初始化的實際效果就是構(gòu)造器。當然它受到了限制:你不能重載實例初始化,所以你只能有一個構(gòu)造器。
        
      從多層嵌套類中訪問外部
      一個內(nèi)部類被嵌套多少層并不重要,它能透明地訪問所有它所嵌入的外圍類的所有成員,如下所示:
      class MNA {
      private void f() {}
      class A {
      private void g() {}
      public class B {
      void h() {
      g();
      f();
                  }
              }
          }
      }
      public class MultiNestingAccess {
      public static void main(String[] args) {
      MNA mna = new MNA();
      MNA.A mnaa = mna.new A();
      MNA.A.B mnaab = mnaa.new B();
      mnaab.h();
          }
      }
      可以看到在MNA.A.B中,調(diào)用方法g()f()不需要任何條件(即使它們被定義為private)。這個例子同時展示了如何從不同的類里面創(chuàng)建多層嵌套的內(nèi)部類對象的基本語法。“.new”語法能產(chǎn)生正確的作用域,所以你不必在調(diào)用構(gòu)造器時限定類名。
      內(nèi)部類的重載問題
      如果你創(chuàng)建了一個內(nèi)部類,然后繼承其外圍類并重新定義此內(nèi)部類時,會發(fā)生什么呢?也就是說,內(nèi)部類可以被重載嗎?這看起來似乎是個很有用的點子,但是“重載”內(nèi)部類就好像它是外圍類的一個方法,其實并不起什么作用:
      class Egg {
             private Yolk y;
             protectedclass Yolk {
                    public Yolk() {
                           System.out.println("Egg.Yolk()");
                    }
             }
             public Egg() {
                    System.out.println("New Egg()");
                    y = new Yolk();
             }
      }
      publicclass BigEgg extends Egg {
             publicclass Yolk {
                    public Yolk() {
                           System.out.println("BigEgg.Yolk()");
                    }
             }
             publicstaticvoid main(String[] args) {
                    new BigEgg();
             }
      }
      輸出結(jié)果為:
      New Egg()
      Egg.Yolk()
      缺省的構(gòu)造器是編譯器自動生成的,這里是調(diào)用基類的缺省構(gòu)造器。你可能認為既然創(chuàng)建了BigEgg 的對象,那么所使用的應該是被“重載”過的Yolk,但你可以從輸出中看到實際情況并不是這樣的。
      這個例子說明,當你繼承了某個外圍類的時候,內(nèi)部類并沒有發(fā)生什么特別神奇的變化。這兩個內(nèi)部類是完全獨立的兩個實體,各自在自己的命名空間內(nèi)。當然,明確地繼承某個內(nèi)部類也是可以的:
      class Egg2 {
             protected class Yolk {
                    public Yolk() {
                           System.out.println("Egg2.Yolk()");
                    }
                    public void f() {
                           System.out.println("Egg2.Yolk.f()");
                    }
             }
             private Yolk y = new Yolk();
             public Egg2() {
                    System.out.println("New Egg2()");
             }
             public void insertYolk(Yolk yy) {
                    y = yy;
             }
             public void g() {
                    y.f();
             }
      }
      public class BigEgg2 extends Egg2 {
             public class Yolk extends Egg2.Yolk {
                    public Yolk() {
                           System.out.println("BigEgg2.Yolk()");
                    }
                    public void f() {
                           System.out.println("BigEgg2.Yolk.f()");
                    }
             }
             public BigEgg2() {
                    insertYolk(new Yolk());
             }
             public static void main(String[] args) {
                    Egg2 e2 = new BigEgg2();
                    e2.g();
             }
      }
      輸出結(jié)果為:
      Egg2.Yolk()
      New Egg2()
      Egg2.Yolk()
      BigEgg2.Yolk()
      BigEgg2.Yolk.f()
      現(xiàn)在BigEgg2.Yolk 通過extends Egg2.Yolk 明確地繼承了此內(nèi)部類,并且重載了其中的方法。Egg2 insertYolk()方法使得BigEgg2 將它自己的Yolk 對象向上轉(zhuǎn)型,然后傳遞給引用y。所以當g()調(diào)用y.f()時,重載后的新版的f()被執(zhí)行。第二次調(diào)用Egg2.Yolk()BigEgg2.Yolk 的構(gòu)造器調(diào)用了其基類的構(gòu)造器??梢钥吹皆谡{(diào)用g()的時候,新版的f()被調(diào)用了。
      內(nèi)部類的繼承問題thinking in java 3th p294
      因為內(nèi)部類的構(gòu)造器要用到其外圍類對象的引用,所以在你繼承一個內(nèi)部類的時候,事情變得有點復雜。問題在于,那個“秘密的”外圍類對象的引用必須被初始化,而在被繼承的類中并不存在要聯(lián)接的缺省對象。要解決這個問題,需使用專門的語法來明確說清它們之間的關(guān)聯(lián):
      class WithInner {
              class Inner {
                      Inner(){
                              System.out.println("this is a constructor in WithInner.Inner");
                      };
              }
      }
      public class InheritInner extends WithInner.Inner {
              // ! InheritInner() {} // Won't compile
              InheritInner(WithInner wi) {
                      wi.super();
                      System.out.println("this is a constructor in InheritInner");
              }
              public static void main(String[] args) {
                      WithInner wi = new WithInner();
                      InheritInner ii = new InheritInner(wi);
              }
      }
      輸出結(jié)果為:
      this is a constructor in WithInner.Inner
      this is a constructor in InheritInner
      可以看到,InheritInner 只繼承自內(nèi)部類,而不是外圍類。但是當要生成一個構(gòu)造器時,缺省的構(gòu)造器并不算好,而且你不能只是傳遞一個指向外圍類對象的引用。此外,你必須在構(gòu)造器內(nèi)使用如下語法:
      enclosingClassReference.super();
      這樣才提供了必要的引用,然后程序才能編譯通過。

        本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
        轉(zhuǎn)藏 分享 獻花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多