ThinkJava-复用类
生活随笔
收集整理的這篇文章主要介紹了
ThinkJava-复用类
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
7 .2 繼承語法 例子: package com.cy.reusing;import static com.java.util.Print.*;class Cleanser {private String s = "Cleanser";public void append(String a) { s += a; }public void dilute() { append(" dilute()"); }public void apply() { append(" apply()"); }public void scrub() { append(" scrub()"); }public String toString() { return s; }public static void main(String[] args) {Cleanser x = new Cleanser();x.dilute(); x.apply(); x.scrub();print(x);}
} public class Detergent extends Cleanser {// Change a method:public void scrub() {append(" Detergent.scrub()");super.scrub(); // Call base-class version
}// Add methods to the interface:public void foam() { append(" foam()"); }// Test the new class:public static void main(String[] args) {Detergent x = new Detergent();x.dilute();x.apply();x.scrub();x.foam();print(x);print("Testing base class:");Cleanser.main(args);}
}
/* Output:
Cleanser dilute() apply() Detergent.scrub() scrub() foam()
Testing base class:
Cleanser dilute() apply() scrub()
*///:~ View Code Cleanser中所有的方法都必須是public的,這一點非常重要。請記住,如果沒有加任何訪問 權(quán)限修飾詞,那么成員默認(rèn)的訪問權(quán)限是包訪問權(quán)限, 它僅允許包內(nèi)的成員訪問。因此,在此 包中,如果沒有訪問權(quán)限修飾詞,任何人都可以使用這些方法。例如, Detergent就不成問題。 但是,其他包中的某個類若要從CIeanser中繼承,則只能訪問public成員。所以,為了繼承, 一 般的規(guī)則是將所有的數(shù)據(jù)成員都指定為private ,將所有的方法指定為public (稍后將會學(xué)到, protected成員也可以借助導(dǎo)出類來訪問)。當(dāng)然,在特殊情況下,必須做出調(diào)整,但上述方法的 確是一個很有用的規(guī)則。 正如我們在scrub()中所見,使用基類中定義的方法及對它進(jìn)行修改是可行的。在此例中, 你可能想要在新版本中調(diào)用從基類繼承而來的方法。但是在scrub()中,并不能直接調(diào)用scrub() , 因為這樣做將會產(chǎn)生遞歸,而這并不是你所期望的。為解決此問題, Java用super關(guān)鍵字表示超 類的意思,當(dāng)前類就是從超類繼承來的。為此,表達(dá)式super.scrub()將調(diào)用基類版本的scrub() 方法. 7.8 final關(guān)鍵字 7.8.1 final 數(shù)據(jù) 一個既是static又是final的域只占據(jù)一段不能改變的存儲空間。 當(dāng)對對象引用而不是基本類型運用final時, 其含義會有一點令人迷惑。對于基本類型, final使數(shù)值恒定不變; 而用于對象引用, final使引用恒定不.變。一旦引用被初始化指向一個對 象,就無法再把它改為指向另一個對象。然而,對象其自身卻是可以被修改的, Java并未提供 使任何對象恒定不變的途徑(但可以自己編寫類以取得使對象恒定不變的效果)。這一限制同樣 適用數(shù)組,它也是對象。 fínal 參數(shù): Java允許在參數(shù)列表中以聲明的方式將參數(shù)指明為final。這意味著你無法在方法中更改參數(shù) 引用所指向的對象: package com.cy.reusing;class Gizmo {public void spin() {}
}public class FinalArguments {void with(final Gizmo g) {//! g = new Gizmo(); // Illegal -- g is final
}void without(Gizmo g) {g = new Gizmo(); // OK -- g not final
g.spin();}// void f(final int i) { i++; } // Can't change// You can only read from a final primitive:int g(final int i) { return i + 1; }public static void main(String[] args) {FinalArguments bf = new FinalArguments();bf.without(null);bf.with(null);}
} ///:~ View Code 方法f()和g()展示了當(dāng)基本類型的參數(shù)被指明為final時所出現(xiàn)的結(jié)果:你可以讀參數(shù),但卻 無法修改參數(shù).這一特性主要用來向匿名內(nèi)部類傳遞數(shù)據(jù),我們將在第10章中學(xué)習(xí)它. 7.8.2 final 方法 使用final方法的原因有兩個.第一個原因是把方法鎖定,以防任何繼承類修改它的含義. 這是出于設(shè)計的考慮:想要確保在繼承中使方法行為保持不變,并且不會被覆蓋。 過去建議使用final方法的第二個原因是效率。 類中所有的private方法都隱式地指定為是final的。由于無法取用private方法,所以也就無 法覆蓋它.可以對private方法添加final 修飾詞,但這并不能給該方法增加任何額外的意義。 這一問題會造成混淆.因為,如果你試圖覆蓋一個private方法(隱含是final的) ,似乎是奏 效的,而且編譯器也不會繪出錯誤信息: package com.cy.reusing;import static com.java.util.Print.*;class WithFinals {// Identical to "private" alone:private final void f() { print("WithFinals.f()"); }// Also automatically "final":private void g() { print("WithFinals.g()"); }
}class OverridingPrivate extends WithFinals {private final void f() {print("OverridingPrivate.f()");}private void g() {print("OverridingPrivate.g()");}
}class OverridingPrivate2 extends OverridingPrivate {public final void f() {print("OverridingPrivate2.f()");}public void g() {print("OverridingPrivate2.g()");}
}public class FinalOverridingIllusion {public static void main(String[] args) {OverridingPrivate2 op2 = new OverridingPrivate2();op2.f();op2.g();// You can upcast:OverridingPrivate op = op2;// But you can't call the methods://! op.f();//! op.g();// Same here:WithFinals wf = op2;//! wf.f();//! wf.g();
}
}
/* Output:
OverridingPrivate2.f()
OverridingPrivate2.g()
*///:~ View Code "覆蓋"只有在某方法是基類的接口的一部分時才會出現(xiàn)。即,必須能將一個對象向上轉(zhuǎn)型 為它的基本類型并調(diào)用相同的方法(這一點在下一章闡明)。 如果某方法為prlv?te ,它就不是基 類的接口的一部分。它僅是一些隱藏于類中的程序代碼,只不過是具有相同的名稱而已。但如 果在導(dǎo)出類中以相同的名稱生成-個publlc 、protected或包訪問權(quán)限方法的話,該方法就不會產(chǎn) 生在基類中出現(xiàn)的"僅具有相同名稱"的情況。此時你并沒有覆蓋該方法,僅是生成了一個新 的方法。由于private方法無法觸及而且能有效隱藏,所以除了把它看成是因為它所歸屬的類的 組織結(jié)構(gòu)的原因而存在外,其他任何事物都不需要考慮到它。 7.8.3 final 類 當(dāng)將某個類的整體定義為final時(通過將關(guān)鍵字final置于它的定義之前), -就表明了你不打 算繼承該類,而且也不允許別人這樣傲。換句話說,出于某種考慮,你對該類的設(shè)計永不需要 做任何變動,或者出于安全的考慮,你不希望它有子類。 package com.cy.reusing;class SmallBrain {}final class Dinosaur {int i = 7;int j = 1;SmallBrain x = new SmallBrain();void f() {}
}//! class Further extends Dinosaur {}
// error: Cannot extend final class 'Dinosaur'public class Jurassic {public static void main(String[] args) {Dinosaur n = new Dinosaur();n.f();n.i = 40;n.j++;}
} ///:~ View Code 請注意, final類的域可以根據(jù)個人的意愿選擇為是或不是final。不論類是否被定義為final , 相同的規(guī)則都適用于定義為final的域。然而,由于final類禁止繼承,所以final類中所有的方法 都隱式指定為是final的,因為無法覆蓋色們。在final類中可以給方法添加final修飾詞,但這不 會增添任何意義。 7.9 初始化及類的加載 7.9. 1 繼承與初始化 了解包括繼承在內(nèi)的初始化全過程,以對所發(fā)生的一切有個全局性的把握,是很有益的。 請看下例: package com.cy.reusing;import static com.java.util.Print.*;class Insect {private int i = 9;protected int j;Insect() {print("i = " + i + ", j = " + j);j = 39;}private static int x1 = printInit("static Insect.x1 initialized");static int printInit(String s) {print(s);return 47;}
}public class Beetle extends Insect {private int k = printInit("Beetle.k initialized");public Beetle() {print("k = " + k);print("j = " + j);}private static int x2 = printInit("static Beetle.x2 initialized");public static void main(String[] args) {print("Beetle constructor");Beetle b = new Beetle();}
}
/* Output:
static Insect.x1 initialized
static Beetle.x2 initialized
Beetle constructor
i = 9, j = 0
Beetle.k initialized
k = 47
j = 39
*///:~ 在Beetle上運行Java時,所發(fā)生的第-件事情就是試圖訪問Bettle.main() (一個static方法) , 于是加載器開始啟動并找出Beetle類的編譯代碼(在名為BattIe.class的文件之中)。在對它進(jìn)行 加載的過程中,編譯器注意到它有一個基類(這是由關(guān)鍵字extends得知的) .于是它繼續(xù)進(jìn)行加 載。不管你是否打算產(chǎn)生一個該基類的對象,這都要發(fā)生(請嘗試將對象創(chuàng)建代碼注釋掉,以 證明這一點)。 如果該基類還有其自身的基類,那么第二個基類就會被加載,如此類推。接下來,根基類 中的static初始化(在此例中為Insect) 即會被執(zhí)行,然后是下一個導(dǎo)出類,以此類推。這種方 式很重要,因為導(dǎo)出類的static初始化可能會依賴于基類成員能否被正確初始化。 至此為止,必要的類都已加載完畢,對象就可以被創(chuàng)建了。首先,對象中所有的基本類型 都會被設(shè)為默認(rèn)值,對象引用被設(shè)為null——這是通過將對象內(nèi)存設(shè)為二進(jìn)制零值而一舉生成的。 然后,基類的構(gòu)造器會被調(diào)用。在本例中,它是被自動調(diào)用的。但也可以用super來指定對基類 構(gòu)造器的調(diào)用(正如在Beetle()構(gòu)造器中的第一步操作)。基類構(gòu)造器和導(dǎo)出類的構(gòu)造器一樣, 以相同的順序來經(jīng)歷相同的過程。在基類構(gòu)造器完成之后,實例變量按其次序被初始化。最后, 構(gòu)造器的其余部分被執(zhí)行。 ----------------
轉(zhuǎn)載于:https://www.cnblogs.com/tenWood/p/8411979.html
總結(jié)
以上是生活随笔為你收集整理的ThinkJava-复用类的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 关于RF中类似于异常(TRY语句)情况的
- 下一篇: The hierarchy of the