Java程式設計思想(2nd)學習筆記(6) (轉)
第6章 重複運用classes
一.繼承(inheritance)
1. 在derived class中overriding某個時,只能覆寫base class中的介面,即base class中的public或protected或friendly函式。如果試圖overriding一個private函式,雖然編譯透過,但實際上你只是在derived class中新增了一個函式。如
class Cleanser{
private void prt(){//(b)
System.out.println("Cleanser.prt()");
}
}
public class ExplicitStatic extends Cleanser{
public void prt(){
System.out.println("ExplicitStatic.prt()");
}
public static void main(String[] args){
Cleanser x = new ExplicitStatic();
x.prt();//(a)
}
}
因為Cleanser中的prt()是private,所以不能在其derived class中被覆寫。ExplicitStatic中的prt()只是ExplicitStatic中的一個函式,所以當試圖在(a)處透過多型來prt()時,會發生錯誤。如果把(b)處的private去掉,則結果為
ExplicitStatic.prt()
2. Super的使用
1)透過關鍵字super可以呼叫當前class的superclass(父類)。
例6.1.1.1
class Base{
Base(){System.out.println("Base()");}
public void scrub() { System.out.println(" Base.scrub()"); }
}
class Cleanser extends Base{
private String s = new String("Cleanser");
public void append(String a) { s+=a; }
public void dilute() { append(" dilute()"); }
public void apply() { append(" apply()"); }
public void scrub() { append(" scrub()"); }
public void print() { System.out.println(s); }
Cleanser(){
System.out.println("Cleanser(): " + s);
}
public static void testStatic(){
System.out.println("testStatic()");
}
public static void main(String[] args){
Cleanser x = new Cleanser();
x.dilute(); x.apply(); x.scrub(); x.print();
}
}
public class ExplicitStatic extends Cleanser{
ExplicitStatic(){
System.out.println("ExplicitStatic()");
}
public void scrub(){
append(" Detergen.scrub()");
super.testStatic();
super.scrub();//呼叫的是Cleanser.scrub()
}
public void foam() { append(" foam()"); }
public static void main(String[] args){
ExplicitStatic x = new ExplicitStatic();
x.dilute(); x.apply(); x.scrub(); x.foam();
x.print(); System.out.println("Test base class:");
Cleanser.main(args);
testStatic();
}
}
執行結果:
Base()
Cleanser(): Cleanser
ExplicitStatic()
testStatic()
Cleanser dilute() apply() Detergen.scrub() scrub() foam()
Test base class:
Base()
Cleanser(): Cleanser
Cleanser dilute() apply() scrub()
testStatic()
2)透過super來呼叫superclass中的成員時,呼叫的是最近成員。
例6.1.1.2
class Base{
protected String baseS = "Base";//(a)
//private String baseS = "Base";
Base(){System.out.println("Base()");}
}
class Cleanser extends Base{
protected String baseS = "Cleanser";//(b)
public String s = new String("Cleanser");
Cleanser(){
System.out.println("Cleanser(): " + s);
}
Cleanser(String a){
System.out.println("Cleanser(" + a + "): s = " + s );
}
}
public class ExplicitStatic extends Cleanser{
String s2 = s;
String baseS = super.baseS; //(c)
ExplicitStatic(){
super("ExplicitStatic");
System.out.println("ExplicitStatic():s2 = " + s2 + ", baseS = " + baseS + "super.baseS = " + super.baseS);
baseS = "ExplicitStatic";
System.out.println("baseS = " + baseS + " , super.baseS = " + super.baseS);
}
public static void main(String[] args){
ExplicitStatic x = new ExplicitStatic();
}
}
結果1:
Base()
Cleanser(ExplicitStatic): s = Cleanser
ExplicitStatic():s2 = Cleanser, baseS = Cleanser,super.baseS = Cleanser
baseS = ExplicitStatic , super.baseS = Cleanser
在上面例子中,在三個class中都存在String bases例項。在ExplicitStatic中如果直接呼叫baseS,則實際呼叫的是當前類ExplicitStatic中的baseS(即(c)處的成員);如果透過super.bases來呼叫baseS,則呼叫的是離當前類ExplicitStatic最近的baseS成員,即Cleanser class中的baseS例項(即(b)處),產生的結果如結果1所示。如果把(b)處語句註釋掉,則將呼叫Base class中的baseS,結果如結果2所示。
結果2:
Base()
Cleanser(ExplicitStatic): s = Cleanser
ExplicitStatic():s2 = Cleanser, baseS = Base,super.baseS = Base
baseS = ExplicitStatic , super.baseS = Base
3. Base class的初始化
2.1 當你產生derived class時,其中會包含base class子物件(sub)。這個子物件就和你另外產生的base class物件一模一樣。
2.2 透過super()可呼叫base class的建構函式,但必須放在建構函式的第一行,並且只能在建構函式中運用。
2.3 初始化順序為:
1) 載入程式碼(.class)
2) 初始化class的靜態成員,初始化順序了“從裡到外”,即從base class開始。
3) 在derived class的建構函式中呼叫base class的建構函式。
如果在derived class的建構函式中沒有透過super()顯式呼叫呼叫base class的建構函式,會呼叫bass class的default建構函式並自動生成相應的呼叫語句,從而產生一個base class例項。如果在derived class的建構函式中透過super()顯示呼叫了父類的建構函式,則呼叫所指定的建構函式。呼叫建構函式的呼叫順序是“從裡到外”。
4) 呼叫derived class的建構函式。
**:當base class沒有default建構函式時,必須在derived class的建構函式中透過super顯示呼叫base class的建構函式。
例:下面程式碼的初始化過程為:
1) 裝載ExplicitStatic的程式碼(裝載ExplicitStatic.class檔案)。
2) 發現ExplicitStatic有關鍵字extends,裝載ExplicitStatic的base class的程式碼(裝載Cleanser.class檔案)。
3) 發現Cleanser有關鍵字extends,裝載Cleanser的base class的程式碼(裝載Base.class檔案)。
4) 初始化Base class中的靜態成員。
5) 初始化Cleanser class中的靜態成員。
6) 初始化ExplicitStatic class中的靜態成員。
如果把(c)處的程式碼註釋掉,那麼初始化工作到此就結束了。
7) 為ExplicitStatic物件分配空間,並把儲存空間初始化為0。
8) 在ExplicitStatic class的構造中呼叫super("ExplicitStatic")(在ExplicitStatic class的建構函式中顯式呼叫父類的建構函式),試圖產生一個Cleanser class例項。
9) 為Cleanser物件分配儲存空間,並把儲存空間初始化為0。
10) 由於Cleanser class又是繼承自Base class,會在Cleanser class的建構函式中透過super()(由於沒有顯式呼叫父類的建構函式,所以自動呼叫父類的default建構函式)呼叫父類的建構函式,試圖產生一個Cleanser class例項。
11) 產生一個Base class例項。先初始化成員變數,再呼叫建構函式。
12) 回到Cleanser class,產生一個例項。首先初始化Cleanser class中的成員資料,再建構函式Cleanser(String a)中的其餘部分。
13) 回到ExplicitStatic class,產生一個例項。首先初始化ExplicitStatic class中的成員資料,再執行建構函式ExplicitStatic ()中的其餘部分(System.out.println(“ExplicitStatic()”))。
class Base{
static int s1 = prt("s1 initialized.", 11);
int i1 = prt("i1 initialized.", 12);
Base(){
System.out.println("Base()");
System.out.println("s1 = " + s1 + " ,i1 = " + i1);
draw();//(d)
}
void draw(){
System.out.println("base.draw:s1 = " + s1 + " ,i1 = " + i1);
}
static int prt(String s, int num) {
System.out.println(s);
return num;
}
}
class Cleanser extends Base{
static int s2 = prt("s2 initialized.", 21);
int i2 = prt("i2 initialized.", 22);
Cleanser(){
System.out.println("Cleanser()");
System.out.println("s2 = " + s2 + " ,i2 = " + i2);
}
Cleanser(String a){
//super();(b)
System.out.println("Cleanser(" + a + ")");
System.out.println("s2 = " + s2 + " ,i2 = " + i2);
}
void draw(){
System.out.println("Cleanser.draw:s2 = " + s2 + " ,i2 = " + i2);
}
}
public class ExplicitStatic extends Cleanser{
static int s3 = prt("s3 initialized.", 31);
int i3 = prt("i3 initialized", 31);
ExplicitStatic(){
super("ExplicitStatic");//(a)
System.out.println("ExplicitStatic()");
System.out.println("s3 = " + s3 + " ,i3 = " + i3);
}
public static void main(String[] args){
ExplicitStatic x = new ExplicitStatic();//(c)
}
}
結果:
s1 initialized.
s2 initialized.
s3 initialized.
//如果把(c)處的程式碼註釋掉,輸出結果到此為止,不會輸出下面結果
i1 initialized.
Base()
s1 = 11 ,i1 = 12
Cleanser.draw:s2 = 21 ,i2 = 0//(d)處結果
i2 initialized.
Cleanser(ExplicitStatic)//(a)處結果
s2 = 21 ,i2 = 22
i3 initialized
ExplicitStatic()
s3 = 31 ,i3 = 31
由於在Base()中呼叫draw()時,Cleanser中的i2還未進行初始化,而在為Cleanser物件分配儲存空間時,把儲存空間初始化為0,所以此時i2為0。
2.4 程式碼及結果中的(a)說明了是先產生當前class的base class的例項,否則在derived class中無法呼叫base class的成員。在呼叫Cleanser class的建構函式Cleanser(String a)時,在Cleanser(String a)中沒有用super顯式呼叫Base class的建構函式,所以會自動生成呼叫Base class的default建構函式的語句,如(b)。
4. 組合與繼承之間的快擇
. 1)繼承表示的是一種“is-a(是一個)”的關係,如貨車是汽車中的一種;組合表示的是一種“has-a(有一個)”的關係,如汽車有四個輪子。
2)是否需要將新的class向上轉型為base class。
5. 在繼承中的訪問
protect變數能被子孫類所呼叫。如Base class中的baseS能被Cleanser class和ExplicitStatic class呼叫。
class Base{
protected String baseS = "Base";
//private String baseS = "Base";
Base(){System.out.println("Base()");}
}
class Cleanser extends Base{
protected String baseS = "Cleanser";
public String s = new String("Cleanser");
Cleanser(){
System.out.println("Cleanser(): " + s);
}
Cleanser(String a){
System.out.println("Cleanser(" + a + "): s = " + s );
}
}
public class ExplicitStatic extends Cleanser{
String s2 = s;
String baseS = super.baseS;
ExplicitStatic(){
super("ExplicitStatic");
System.out.println("ExplicitStatic():s2 = " + s2 + ", baseS = " + baseS + "super.baseS = " + super.baseS);
baseS = "ExplicitStatic";
System.out.println("baseS = " + baseS + " , super.baseS = " + super.baseS);
}
public static void main(String[] args){
ExplicitStatic x = new ExplicitStatic();
}
}
結果:
Base()
Cleanser(ExplicitStatic): s = Cleanser
ExplicitStatic():s2 = Cleanser, baseS = Cleanser, super.baseS = Cleanser
baseS = ExplicitStatic , super.baseS = Cleanser
二.關鍵字final
1.Final data
1.1 final data
1)當基本型別被定義為final,表示它的資料值不能被改變。如
final int i = 9;
i++;//編譯錯誤,不能改變I的值
2) 當object reference被定義為final時,不能改變的只是reference而不是物件本身。如
class Value{
int i = 1;
}
public class ExplicitStatic extends Cleanser{
public static void main(String[] args){
final Value v = new Value();//v.i = 1
v.i++;//v.i = 2
//v = new Value();
}
}
由於v為final,所以不能透過new Value()使v重新指向一個物件;但是v所指向的物件的值是可以改變的(v.i++)。
1.2 blank finals
我們可以將資料成員宣告為final但不給予初值,這就是blank finals。但blank finals必須且只能在建構函式中進行初始化。
public class ExplicitStatic {
final int ib;
final int i = 1;
ExplicitStatic()
{
ib = 2;//(a)
//i = 3; (b)
System.out.println("i = " + i + ", ib = " + ib);
}
public static void main(String[] args){
ExplicitStatic ex = new ExplicitStatic();
}
}
ib為blank finals,所以可以在建構函式中進行初始化。如果把(a)處的程式碼註釋掉,則ib沒有初值,編譯出錯。而i在定義處已進行了初始化,則不能改變i的值,(b)處的程式碼編譯錯誤。
**:非blank finals成員即使在建構函式中也不能更改其值
2.Final methods
1)被宣告為final的函式不能被覆寫
2)class中所有private函式自然而然會是final。
1. Final classes
1)當一個class被宣告為final時,表示它不能被繼承,但class的資料成員不是final,可以被改變。如
class SmallBrain{}
:namespace prefix = o ns = "urn:schemas--com::office" />
final class Dinosaur{
int i = 7;
int j = i;
SmallBrain x = new SmallBrain();
void f(){};
}
//不能繼承final函式
//class Further extends Dinosaur{}
public class ExplicitStatic{
public static void main(String[] args){
Dinosaur n = new Dinosaur();
n.f();
n.i = 40;//final class中的non-final資料成員可以被改變
n.j++;
}
}
2)final class中的所有函式也都自然是final,因為沒有人能夠加以覆寫。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-962957/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Java程式設計思想學習筆記1 - 內部類Java程式設計筆記
- Java程式設計思想學習筆記4 - 序列化技術Java程式設計筆記
- Java 程式設計思想筆記:Learn 10Java程式設計筆記
- 《Java程式設計思想》筆記08——持有物件Java程式設計筆記物件
- 《Java程式設計思想》讀書筆記一Java程式設計筆記
- 讀書筆記-Java程式設計思想-03筆記Java程式設計
- 《Java程式設計思想》筆記8.多型Java程式設計筆記多型
- 《Java程式設計思想》筆記07——內部類Java程式設計筆記
- Python學習筆記之 Python設計思想&設計原則Python筆記
- java學習筆記6Java筆記
- Spring 學習筆記(6)Spring和資料庫程式設計Spring筆記資料庫程式設計
- Linux學習/TCP程式設計學習筆記LinuxTCP程式設計筆記
- 網路程式設計學習筆記程式設計筆記
- 重學Java設計模式-學習筆記(1)Java設計模式筆記
- java程式設計師程式設計筆試基礎學習Java程式設計師筆試
- Java併發程式設計學習筆記----執行緒池Java程式設計筆記執行緒
- 程式設計基礎·Java學習筆記·物件導向(下)程式設計Java筆記物件
- 《圖解 Google V8》設計思想篇——學習筆記(一)圖解Go筆記
- Java設計模式學習筆記(一) 設計模式概述Java設計模式筆記
- spark學習筆記--進階程式設計Spark筆記程式設計
- Javascript高階程式設計 學習筆記JavaScript程式設計筆記
- ROS串列埠程式設計學習筆記ROS串列埠程式設計筆記
- 結構化程式設計--學習筆記程式設計筆記
- Golang 學習筆記——tun/tap 程式設計Golang筆記程式設計
- JAVA程式設計學習記錄(安裝Java)Java程式設計
- 四. 文字程式設計--Windows程式設計課程學習筆記程式設計Windows筆記
- JAVA語言程式設計思想Java程式設計
- 好程式設計師web前端培訓學習筆記Vue學習筆記一程式設計師Web前端筆記Vue
- Vue學習筆記(九):元件化程式設計Vue筆記元件化程式設計
- python程式設計學習筆記⑦-1函式Python程式設計筆記函式
- 好程式設計師學習筆記:函式程式設計師筆記函式
- 設計模式學習筆記設計模式筆記
- 學習筆記-設計模式筆記設計模式
- Java設計模式學習筆記(五) 單例模式Java設計模式筆記單例
- 好程式設計師web前端培訓學習筆記Vue學習筆記之二程式設計師Web前端筆記Vue
- JAVA程式設計學習記錄(JavaWeb-Html)Java程式設計WebHTML
- Java 基礎程式設計筆記Java程式設計筆記
- Node.js 設計模式 學習筆記 之 流程式設計Node.js設計模式筆記程式設計
- JavaScript DOM 程式設計藝術 學習筆記01JavaScript程式設計筆記