久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

Java內(nèi)部類總結(jié)

 @IT小小鳥@ 2012-01-14

Java內(nèi)部類總結(jié)

內(nèi)部類是指在一個(gè)外部類的內(nèi)部再定義一個(gè)類。內(nèi)部類作為外部類的一個(gè)成員,,并且依附于外部類而存在的,。內(nèi)部類可為靜態(tài),可用protected和private修飾(而外部類只能使用public和缺省的包訪問(wèn)權(quán)限),。內(nèi)部類主要有以下幾類:成員內(nèi)部類,、局部?jī)?nèi)部類、靜態(tài)內(nèi)部類,、匿名內(nèi)部類

  為什么需要內(nèi)部類,?

  典型的情況是,內(nèi)部類繼承自某個(gè)類或?qū)崿F(xiàn)某個(gè)接口,,內(nèi)部類的代碼操作創(chuàng)建其的外圍類的對(duì)象。所以你可以認(rèn)為內(nèi)部類提供了某種進(jìn)入其外圍類的窗口,。使用內(nèi)部類最吸引人的原因是:

  每個(gè)內(nèi)部類都能獨(dú)立地繼承自一個(gè)(接口的)實(shí)現(xiàn),,所以無(wú)論外圍類是否已經(jīng)繼承了某個(gè)(接口的)實(shí)現(xiàn),對(duì)于內(nèi)部類都沒(méi)有影響,。如果沒(méi)有內(nèi)部類提供的可以繼承多個(gè)具體的或抽象的類的能力,,一些設(shè)計(jì)與編程問(wèn)題就很難解決。從這個(gè)角度看,,內(nèi)部類使得多重繼承的解決方案變得完整,。接口解決了部分問(wèn)題,而內(nèi)部類有效地實(shí)現(xiàn)了“多重繼承”,。

  A:成員內(nèi)部類

  作為外部類的一個(gè)成員存在,,與外部類的屬性、方法并列,。

publicclass Outer {
privatestaticinti = 1;
privateintj = 10;
privateintk = 20;

publicstaticvoidouter_f1() {
}

publicvoidouter_f2() {
}

// 成員內(nèi)部類中,,不能定義靜態(tài)成員
// 成員內(nèi)部類中,可以訪問(wèn)外部類的所有成員
class Inner {
// static int inner_i = 100; //內(nèi)部類中不允許定義靜態(tài)變量
intj = 100; // 內(nèi)部類和外部類的實(shí)例變量可以共存
intinner_i = 1;

void inner_f1() {
System.out.println(i);
//在內(nèi)部類中訪問(wèn)內(nèi)部類自己的變量直接用變量名
System.out.println(j);
//在內(nèi)部類中訪問(wèn)內(nèi)部類自己的變量也可以用this.變量名
System.out.println(this.j);
//在內(nèi)部類中訪問(wèn)外部類中與內(nèi)部類同名的實(shí)例變量用外部類名.this.變量名
System.out.println(Outer.this.j);
//如果內(nèi)部類中沒(méi)有與外部類同名的變量,,則可以直接用變量名訪問(wèn)外部類變量
System.out.println(k);
outer_f1();
outer_f2();
}
}

//外部類的非靜態(tài)方法訪問(wèn)成員內(nèi)部類
publicvoidouter_f3() {
Inner inner = new Inner();
inner.inner_f1();
}

// 外部類的靜態(tài)方法訪問(wèn)成員內(nèi)部類,,與在外部類外部訪問(wèn)成員內(nèi)部類一樣
publicstaticvoidouter_f4() {
//step1 建立外部類對(duì)象
Outer out = new Outer();
//step2 根據(jù)外部類對(duì)象建立內(nèi)部類對(duì)象
Inner inner = out.new Inner();
//step3 訪問(wèn)內(nèi)部類的方法
inner.inner_f1();
}

publicstaticvoid main(String[] args) {
//outer_f4(); //該語(yǔ)句的輸出結(jié)果和下面三條語(yǔ)句的輸出結(jié)果一樣
//如果要直接創(chuàng)建內(nèi)部類的對(duì)象,不能想當(dāng)然地認(rèn)為只需加上外圍類Outer的名字,,
//就可以按照通常的樣子生成內(nèi)部類的對(duì)象,,而是必須使用此外圍類的一個(gè)對(duì)象來(lái)
//創(chuàng)建其內(nèi)部類的一個(gè)對(duì)象:
//Outer.Inner outin = out.new Inner()
//因此,,除非你已經(jīng)有了外圍類的一個(gè)對(duì)象,否則不可能生成內(nèi)部類的對(duì)象,。因?yàn)榇?br> //內(nèi)部類的對(duì)象會(huì)悄悄地鏈接到創(chuàng)建它的外圍類的對(duì)象,。如果你用的是靜態(tài)的內(nèi)部類,
//那就不需要對(duì)其外圍類對(duì)象的引用,。
Outer out = new Outer();
Outer.Inner outin = out.new Inner();
outin.inner_f1();
}
}

  注意:內(nèi)部類是一個(gè)編譯時(shí)的概念,,一旦編譯成功,就會(huì)成為完全不同的兩類,。對(duì)于一個(gè)名為outer的外部類和其內(nèi)部定義的名為inner的內(nèi)部類,。編譯完成后出現(xiàn)outer.class和outer$inner.class兩類。

  B:局部?jī)?nèi)部類

  在方法中定義的內(nèi)部類稱為局部?jī)?nèi)部類,。與局部變量類似,,局部?jī)?nèi)部類不能有訪問(wèn)說(shuō)明符,因?yàn)樗皇峭鈬惖囊徊糠?,但是它可以訪問(wèn)當(dāng)前代碼塊內(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)部類沒(méi)有與外部類同名的變量,,在內(nèi)部類中可以直接訪問(wèn)外部類的實(shí)例變量
System.out.println(out_i);
//可以訪問(wèn)外部類的局部變量(即方法內(nèi)的變量),,但是變量必須是final的
System.out.println(j);
//System.out.println(i);
//如果內(nèi)部類中有與外部類同名的變量,直接用變量名訪問(wèn)的是內(nèi)部類的變量
System.out.println(s);
//用this.變量名訪問(wèn)的也是內(nèi)部類變量
System.out.println(this.s);
//用外部類名.this.內(nèi)部類變量名訪問(wèn)的是外部類變量
System.out.println(Outer.this.s);
}
}
new Inner(k);
}

publicstaticvoid main(String[] args) {
// 訪問(wèn)局部?jī)?nèi)部類必須先有外部類對(duì)象
Outer out = new Outer();
out.f(3);
}
}

  C:靜態(tài)內(nèi)部類(嵌套類):(注意:前兩種內(nèi)部類與變量類似,,所以可以對(duì)照參考變量)

  如果你不需要內(nèi)部類對(duì)象與其外圍類對(duì)象之間有聯(lián)系,,那你可以將內(nèi)部類聲明為static。這通常稱為嵌套類(nested class),。想要理解static應(yīng)用于內(nèi)部類時(shí)的含義,,你就必須記住,普通的內(nèi)部類對(duì)象隱含地保存了一個(gè)引用,,指向創(chuàng)建它的外圍類對(duì)象,。然而,當(dāng)內(nèi)部類是static的時(shí),,就不是這樣了,。嵌套類意味著:

  1. 要?jiǎng)?chuàng)建嵌套類的對(duì)象,并不需要其外圍類的對(duì)象,。
  2. 不能從嵌套類的對(duì)象中訪問(wèn)非靜態(tài)的外圍類對(duì)象,。

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)部類只能訪問(wèn)外部類的靜態(tài)成員(包括靜態(tài)變量和靜態(tài)方法)
System.out.println("Outer.i" + i);
outer_f1();
}

voidinner_f2() {
// 靜態(tài)內(nèi)部類不能訪問(wèn)外部類的非靜態(tài)成員(包括非靜態(tài)變量和非靜態(tài)方法)
// System.out.println("Outer.i"+j);
// outer_f2();
}
}

publicvoidouter_f3() {
// 外部類訪問(wèn)內(nèi)部類的靜態(tài)成員:內(nèi)部類.靜態(tài)成員
System.out.println(Inner.inner_i);
Inner.inner_f1();
// 外部類訪問(wèn)內(nèi)部類的非靜態(tài)成員:實(shí)例化內(nèi)部類即可
Inner inner = new Inner();
inner.inner_f2();
}

publicstaticvoid main(String[] args) {
newOuter().outer_f3();
}
}

  生成一個(gè)靜態(tài)內(nèi)部類不需要外部類成員:這是靜態(tài)內(nèi)部類和成員內(nèi)部類的區(qū)別。靜態(tài)內(nèi)部類的對(duì)象可以直接生成:Outer.Inner in = new Outer.Inner(); 而不需要通過(guò)生成外部類對(duì)象來(lái)生成,。這樣實(shí)際上使靜態(tài)內(nèi)部類成為了一個(gè)頂級(jí)類(正常情況下,,你不能在接口內(nèi)部放置任何代碼,但嵌套類可以作為接口的一部分,,因?yàn)樗莝tatic 的,。只是將嵌套類置于接口的命名空間內(nèi),,這并不違反接口的規(guī)則)

  D:匿名內(nèi)部類(from thinking in java 3th)

  簡(jiǎn)單地說(shuō):匿名內(nèi)部類就是沒(méi)有名字的內(nèi)部類。什么情況下需要使用匿名內(nèi)部類,?如果滿足下面的一些條件,,使用匿名內(nèi)部類是比較合適的:

  ·只用到類的一個(gè)實(shí)例。
  ·類在定義后馬上用到,。
  ·類非常?。⊿UN推薦是在4行代碼以下)
  ·給類命名并不會(huì)導(dǎo)致你的代碼更容易被理解。
  在使用匿名內(nèi)部類時(shí),,要記住以下幾個(gè)原則:
  ·匿名內(nèi)部類不能有構(gòu)造方法,。
  ·匿名內(nèi)部類不能定義任何靜態(tài)成員、方法和類,。
  ·匿名內(nèi)部類不能是public,protected,private,static,。
  ·只能創(chuàng)建匿名內(nèi)部類的一個(gè)實(shí)例。
·一個(gè)匿名內(nèi)部類一定是在new的后面,,用其隱含實(shí)現(xiàn)一個(gè)接口或?qū)崿F(xiàn)一個(gè)類,。
  ·因匿名內(nèi)部類為局部?jī)?nèi)部類,所以局部?jī)?nèi)部類的所有限制都對(duì)其生效,。

  下面的例子看起來(lái)有點(diǎn)奇怪:

//在方法中返回一個(gè)匿名內(nèi)部類
public class Parcel6 {
public Contents cont() {
return new Contents() {
private int i = 11;

public int value() {
return i;
}
}; // 在這里需要一個(gè)分號(hào)
}

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

  cont()方法將下面兩個(gè)動(dòng)作合并在一起:返回值的生成,,與表示這個(gè)返回值的類的定義!進(jìn)一步說(shuō),,這個(gè)類是匿名的,,它沒(méi)有名字。更糟的是,,看起來(lái)是你正要?jiǎng)?chuàng)建一個(gè)Contents對(duì)象:

return new Contents()

  但是,在到達(dá)語(yǔ)句結(jié)束的分號(hào)之前,,你卻說(shuō):“等一等,,我想在這里插入一個(gè)類的定義”:

return new Contents() {
private int i = 11;
public int value() { return i; }
};

  這種奇怪的語(yǔ)法指的是:“創(chuàng)建一個(gè)繼承自Contents的匿名類的對(duì)象?!蓖ㄟ^(guò)new 表達(dá)式返回的引用被自動(dòng)向上轉(zhuǎn)型為對(duì)Contents的引用,。匿名內(nèi)部類的語(yǔ)法是下面例子的簡(jiǎn)略形式:

class MyContents implements Contents {
private int i = 11;
public int value() { return i; }
}
return new MyContents();

  在這個(gè)匿名內(nèi)部類中,使用了缺省的構(gòu)造器來(lái)生成Contents,。下面的代碼展示的是,,如果你的基類需要一個(gè)有參數(shù)的構(gòu)造器,應(yīng)該怎么辦:

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)單地傳遞合適的參數(shù)給基類的構(gòu)造器即可,,這里是將x 傳進(jìn)new Wrapping(x),。在匿名內(nèi)部類末尾的分號(hào),并不是用來(lái)標(biāo)記此內(nèi)部類結(jié)束(C++中是那樣),。實(shí)際上,,它標(biāo)記的是表達(dá)式的結(jié)束,,只不過(guò)這個(gè)表達(dá)式正巧包含了內(nèi)部類罷了。因此,,這與別的地方使用的分號(hào)是一致的,。

  如果在匿名類中定義成員變量,你同樣能夠?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");
}
}

  如果你有一個(gè)匿名內(nèi)部類,,它要使用一個(gè)在它的外部定義的對(duì)象,,編譯器會(huì)要求其參數(shù)引用是final 型的,就像dest()中的參數(shù),。如果你忘記了,,會(huì)得到一個(gè)編譯期錯(cuò)誤信息。如果只是簡(jiǎn)單地給一個(gè)成員變量賦值,,那么此例中的方法就可以了,。但是,如果你想做一些類似構(gòu)造器的行為,,該怎么辦呢,?在匿名類中不可能有已命名的構(gòu)造器(因?yàn)樗緵](méi)名字!),,但通過(guò)實(shí)例初始化,,你就能夠達(dá)到為匿名內(nèi)部類“制作”一個(gè)構(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 的,。因?yàn)閕 被傳遞給匿名類的基類的構(gòu)造器,它并不會(huì)在匿名類內(nèi)部被直接使用,。下例是帶實(shí)例初始化的“parcel”形式,。注意dest()的參數(shù)必須是final,因?yàn)樗鼈兪窃谀涿悆?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);
}
}

  在實(shí)例初始化的部分,,你可以看到有一段代碼,那原本是不能作為成員變量初始化的一部分而執(zhí)行的(就是if 語(yǔ)句),。所以對(duì)于匿名類而言,,實(shí)例初始化的實(shí)際效果就是構(gòu)造器。當(dāng)然它受到了限制:你不能重載實(shí)例初始化,,所以你只能有一個(gè)構(gòu)造器,。

  從多層嵌套類中訪問(wèn)外部

  一個(gè)內(nèi)部類被嵌套多少層并不重要,它能透明地訪問(wèn)所有它所嵌入的外圍類的所有成員,,如下所示:

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)。這個(gè)例子同時(shí)展示了如何從不同的類里面創(chuàng)建多層嵌套的內(nèi)部類對(duì)象的基本語(yǔ)法?!?new”語(yǔ)法能產(chǎn)生正確的作用域,,所以你不必在調(diào)用構(gòu)造器時(shí)限定類名。

  內(nèi)部類的重載問(wèn)題

  如果你創(chuàng)建了一個(gè)內(nèi)部類,,然后繼承其外圍類并重新定義此內(nèi)部類時(shí),,會(huì)發(fā)生什么呢?也就是說(shuō),,內(nèi)部類可以被重載嗎,?這看起來(lái)似乎是個(gè)很有用的點(diǎn)子,但是“重載”內(nè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();
}
}


  輸出結(jié)果為:

New Egg()
Egg.Yolk()

  缺省的構(gòu)造器是編譯器自動(dòng)生成的,,這里是調(diào)用基類的缺省構(gòu)造器。你可能認(rèn)為既然創(chuàng)建了BigEgg 的對(duì)象,,那么所使用的應(yīng)該是被“重載”過(guò)的Yolk,,但你可以從輸出中看到實(shí)際情況并不是這樣的。

  這個(gè)例子說(shuō)明,,當(dāng)你繼承了某個(gè)外圍類的時(shí)候,,內(nèi)部類并沒(méi)有發(fā)生什么特別神奇的變化。這兩個(gè)內(nèi)部類是完全獨(dú)立的兩個(gè)實(shí)體,,各自在自己的命名空間內(nèi),。當(dāng)然,明確地繼承某個(gè)內(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 通過(guò)extends Egg2.Yolk 明確地繼承了此內(nèi)部類,,并且重載了其中的方法,。Egg2 的insertYolk()方法使得BigEgg2 將它自己的Yolk 對(duì)象向上轉(zhuǎn)型,然后傳遞給引用y,。所以當(dāng)g()調(diào)用y.f()時(shí),,重載后的新版的f()被執(zhí)行。第二次調(diào)用Egg2.Yolk()是BigEgg2.Yolk 的構(gòu)造器調(diào)用了其基類的構(gòu)造器,??梢钥吹皆谡{(diào)用g()的時(shí)候,新版的f()被調(diào)用了,。

  內(nèi)部類的繼承問(wèn)題(thinking in java 3th p294)

  因?yàn)閮?nèi)部類的構(gòu)造器要用到其外圍類對(duì)象的引用,,所以在你繼承一個(gè)內(nèi)部類的時(shí)候,,事情變得有點(diǎn)復(fù)雜,。問(wèn)題在于,那個(gè)“秘密的”外圍類對(duì)象的引用必須被初始化,,而在被繼承的類中并不存在要聯(lián)接的缺省對(duì)象,。要解決這個(gè)問(wè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);
}
}

  輸出結(jié)果為:

this is a constructor in WithInner.Inner
this is a constructor in InheritInner

  可以看到,InheritInner 只繼承自內(nèi)部類,,而不是外圍類,。但是當(dāng)要生成一個(gè)構(gòu)造器時(shí),缺省的構(gòu)造器并不算好,,而且你不能只是傳遞一個(gè)指向外圍類對(duì)象的引用,。此外,你必須在構(gòu)造器內(nèi)使用如下語(yǔ)法:

enclosingClassReference.super();

  這樣才提供了必要的引用,,然后程序才能編譯通過(guò),。

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

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多