欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
[轉載]詳析內部類(lèi)

[轉載]詳析內部類(lèi)

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

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

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

下面的例子看起來(lái)有點(diǎn)奇怪:
//在方法中返回一個(gè)匿名內部類(lèi)
public class Parcel6 {
        public Contents cont() {
                return new Contents() {
                     private int i = 11;
                     public int value() {
                            return i;
                     }
              }; // 在這里需要一個(gè)分號
        }
        public static void main(String[] args) {
                Parcel6 p = new Parcel6();
                Contents c = p.cont();
        }
}
cont()方法將下面兩個(gè)動(dòng)作合并在一起:返回值的生成,與表示這個(gè)返回值的類(lèi)的定義!進(jìn)一步說(shuō),這個(gè)類(lèi)是匿名的,它沒(méi)有名字。更糟的是,看起來(lái)是你正要創(chuàng )建一個(gè)Contents對象:
return new Contents()
但是,在到達語(yǔ)句結束的分號之前,你卻說(shuō):“等一等,我想在這里插入一個(gè)類(lèi)的定義”:
return new Contents() {
private int i = 11;
public int value() { return i; }
};
這種奇怪的語(yǔ)法指的是:“創(chuàng )建一個(gè)繼承自Contents的匿名類(lèi)的對象。”通過(guò)new 表達式返回的引用被自動(dòng)向上轉型為對Contents的引用。匿名內部類(lèi)的語(yǔ)法是下面例子的簡(jiǎn)略形式:
class MyContents implements Contents {
private int i = 11;
public int value() { return i; }
    }
return new MyContents();
在這個(gè)匿名內部類(lèi)中,使用了缺省的構造器來(lái)生成Contents。下面的代碼展示的是,如果你的基類(lèi)需要一個(gè)有參數的構造器,應該怎么辦:
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);
    }
}
只需簡(jiǎn)單地傳遞合適的參數給基類(lèi)的構造器即可,這里是將x 傳進(jìn)new Wrapping(x)。在匿名內部類(lèi)末尾的分號,并不是用來(lái)標記此內部類(lèi)結束(C++中是那樣)。實(shí)際上,它標記的是表達式的結束,只不過(guò)這個(gè)表達式正巧包含了內部類(lèi)罷了。因此,這與別的地方使用的分號是一致的。
如果在匿名類(lèi)中定義成員變量,你同樣能夠對其執行初始化操作:
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");
    }
}
如果你有一個(gè)匿名內部類(lèi),它要使用一個(gè)在它的外部定義的對象,編譯器會(huì )要求其參數引用是final 型的,就像dest()中的參數。如果你忘記了,會(huì )得到一個(gè)編譯期錯誤信息。如果只是簡(jiǎn)單地給一個(gè)成員變量賦值,那么此例中的方法就可以了。但是,如果你想做一些類(lèi)似構造器的行為,該怎么辦呢?在匿名類(lèi)中不可能有已命名的構造器(因為它根本沒(méi)名字?。?,但通過(guò)實(shí)例初始化,你就能夠達到為匿名內部類(lèi)“制作”一個(gè)構造器的效果。像這樣做:
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 被傳遞給匿名類(lèi)的基類(lèi)的構造器,它并不會(huì )在匿名類(lèi)內部被直接使用。下例是帶實(shí)例初始化的“parcel”形式。注意dest()的參數必須是final,因為它們是在匿名類(lè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);
    }
}
在實(shí)例初始化的部分,你可以看到有一段代碼,那原本是不能作為成員變量初始化的一部分而執行的(就是if 語(yǔ)句)。所以對于匿名類(lèi)而言,實(shí)例初始化的實(shí)際效果就是構造器。當然它受到了限制:你不能重載實(shí)例初始化,所以你只能有一個(gè)構造器。
  
從多層嵌套類(lèi)中訪(fǎng)問(wèn)外部
一個(gè)內部類(lèi)被嵌套多少層并不重要,它能透明地訪(fǎng)問(wèn)所有它所嵌入的外圍類(lè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中,調用方法g()f()不需要任何條件(即使它們被定義為private)。這個(gè)例子同時(shí)展示了如何從不同的類(lèi)里面創(chuàng )建多層嵌套的內部類(lèi)對象的基本語(yǔ)法。“.new”語(yǔ)法能產(chǎn)生正確的作用域,所以你不必在調用構造器時(shí)限定類(lèi)名。
內部類(lèi)的重載問(wèn)題
如果你創(chuàng )建了一個(gè)內部類(lèi),然后繼承其外圍類(lèi)并重新定義此內部類(lèi)時(shí),會(huì )發(fā)生什么呢?也就是說(shuō),內部類(lèi)可以被重載嗎?這看起來(lái)似乎是個(gè)很有用的點(diǎn)子,但是“重載”內部類(lèi)就好像它是外圍類(lèi)的一個(gè)方法,其實(shí)并不起什么作用:
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();
       }
}
輸出結果為:
New Egg()
Egg.Yolk()
缺省的構造器是編譯器自動(dòng)生成的,這里是調用基類(lèi)的缺省構造器。你可能認為既然創(chuàng )建了BigEgg 的對象,那么所使用的應該是被“重載”過(guò)的Yolk,但你可以從輸出中看到實(shí)際情況并不是這樣的。
這個(gè)例子說(shuō)明,當你繼承了某個(gè)外圍類(lèi)的時(shí)候,內部類(lèi)并沒(méi)有發(fā)生什么特別神奇的變化。這兩個(gè)內部類(lèi)是完全獨立的兩個(gè)實(shí)體,各自在自己的命名空間內。當然,明確地繼承某個(gè)內部類(lè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();
       }
}
輸出結果為:
Egg2.Yolk()
New Egg2()
Egg2.Yolk()
BigEgg2.Yolk()
BigEgg2.Yolk.f()
現在BigEgg2.Yolk 通過(guò)extends Egg2.Yolk 明確地繼承了此內部類(lèi),并且重載了其中的方法。Egg2 insertYolk()方法使得BigEgg2 將它自己的Yolk 對象向上轉型,然后傳遞給引用y。所以當g()調用y.f()時(shí),重載后的新版的f()被執行。第二次調用Egg2.Yolk()BigEgg2.Yolk 的構造器調用了其基類(lèi)的構造器??梢钥吹皆谡{用g()的時(shí)候,新版的f()被調用了。
內部類(lèi)的繼承問(wèn)題thinking in java 3th p294
因為內部類(lèi)的構造器要用到其外圍類(lèi)對象的引用,所以在你繼承一個(gè)內部類(lèi)的時(shí)候,事情變得有點(diǎn)復雜。問(wèn)題在于,那個(gè)“秘密的”外圍類(lèi)對象的引用必須被初始化,而在被繼承的類(lèi)中并不存在要聯(lián)接的缺省對象。要解決這個(gè)問(wèn)題,需使用專(zhuān)門(mén)的語(yǔ)法來(lái)明確說(shuō)清它們之間的關(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);
        }
}
輸出結果為:
this is a constructor in WithInner.Inner
this is a constructor in InheritInner
可以看到,InheritInner 只繼承自?xún)炔款?lèi),而不是外圍類(lèi)。但是當要生成一個(gè)構造器時(shí),缺省的構造器并不算好,而且你不能只是傳遞一個(gè)指向外圍類(lèi)對象的引用。此外,你必須在構造器內使用如下語(yǔ)法:
enclosingClassReference.super();
這樣才提供了必要的引用,然后程序才能編譯通過(guò)。
本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
Java類(lèi)的方法總結(目前最火的9種方法總結梳理)
一個(gè)讓98%的Java程序員犯難的偏門(mén)問(wèn)題
100多道經(jīng)典的JAVA面試題及答案解析(2)
(教學(xué)思路 C#之類(lèi)四)構造方法(靜態(tài)構造方法、this、方法重載)、析構方法(修改新增)...
第3章 面向對象的核心特征
子類(lèi)對象的實(shí)例化過(guò)程
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久