5.3 Explain the effect of modifiers on inheritance with respect to constructors, instance or static variables, and instance or static methods.
5.4 Given a scenario, develop code that declares and/or invokes overridden or overloaded methods and code that declares and/or invokes superclass, overridden, or overloaded constructors.
物件要建構出來一定需要靠constructor
不能只呼叫class本身的constructor,因為所有superclass的constructor也都一定會被呼叫
當使用new()的時候其實就是在使用constructor(也有可能是初始區塊的程式碼)
Constructor basic idea
- 所有的class(including abstract class)都一定會有constructor- constructor看起來會像以下的範例:
public class Bicycle { Bicycle() {} }
- 名稱必須和class相同
- 沒有return type
- constructor可以被overload
- constructor的目的:為了初始化instance variable state
public class Bicycle{ int gear; int cadence; public Bicycle(int gear, int cadence) { this.gear = gear; this.cadence = cadence; } }
Bicycle b = new Bicycle();
因為在Bicycle class並不存在不需要parameter的constructor。
Constructor連鎖反應
Bike b = new Bike();
假如繼承關係為Bike->Car->Object,則當new的時候發生了以下幾項事件:
- Bike的constructor被呼叫,並暗中執行super()以呼叫所有superclass的constructor,除非bike的constructor呼叫overload的constructor
- Car的constructor被呼叫
- Object的constructor被呼叫
- Object的instance variable被給了explicit values(明確值)。如x=1,1是x的explicit value
- 完成Object的constructor
- Car的instance variable被給了explicit values(if exists)
- 完成Car的constructor
- Bike的instance variable被給了explicit values(if exists)
- 完成Bike的constructor
Job stack如下:
|--------------------------------
|4. Object()
|---------------------------------
|3. Car() call super()
|---------------------------------
|2. Bike() call super()
|---------------------------------
|1. Main call new Bike()
|---------------------------------
constructor rules:
- constructor可以使用任何的access modifiers(包含private)。如果是private,這代表只有class內部能夠實體化class的object。假如有一個private constructor想要讓其他人使用instance,則需要透過static method or static variable,這樣才可以存取此class的instance
- 名稱必須和class相同
- 沒有return type
- 可以建立construct的overloading method但不是constructor(but stupid),因為這就是一個method。使用和class同名的method要小心,也許會誤認為是constructor(簡單方法確認:是否有return value)
- 只有當class內一個constructor都沒有,compiler才會幫忙建立default constructor,而這個default constructor一定是不帶任何parameter
- 如果已經建立一個帶parameter的constructor,compiler不會幫忙建立default constructor。此時如果還需要一個不帶parameter的constructor,則需要自己建立。
- 每一個constructor在第一行一定會有super()或this(),constructor會根據情況自己安插。
- 如果自己寫了一個constructor(非compiler建立的default constructor)沒有帶super()或this(),constructor會自動插入super()
- 自己寫super()的時候可以帶參數,但要看superclass提供哪些constructors
- 直到superclass的constructor完成之前,你不能呼叫instance method,或存取instance variable。
- 只有static variable和method可以被包在super()或this()裡面呼叫(ex:super(Animal.NAME))
- abstract class也有constructor,當concrete class被實體化的時候,也會被呼叫
- interface沒有constructor,且interface不屬於inheritance tree的任何一部份
- 唯一直接呼叫constructor(非透過new()的方法,而是把constructor當成一個method)是在另外一個constructor裡面呼叫,但注意必須必須要用this或super
public class Foo { private int f; public Foo() { this(1); } public Foo(int f) { this.f = f; } }
Default Constructor
再重申一次,只有當class內一個constructor都沒有,compiler才會幫忙建立default constructor,而這個default constructor一定是不帶任何parameter
- default constructor的樣子
- access modifier和class的相同
- 沒有parameters
- 以不帶arguments的方式呼叫superclass的constructor(super())
- 範例1
Class Car{}
則default constructor為:
Class Car{ Car(){ super(); } }
注意constructor的access modifier也是default,和class一樣
compiler還是會建立不帶parameters的super()
注意!雖然super()是compiler自動加入,但如果這個時候superclass並沒有不帶parameters的constructor,則compiler會失敗,告知沒有default constructor available for Car。
最後謹記,constructor是不能被override(因為不是method,只有method可以被extend+override),但constructor是可以被overload的。
Overloading Constructor
- 範例2
public Class Car{}
則default constructor為:
public Class Car{ public Car(){ super(); } }
注意constructor的access modifier也是publix,和class一樣
- 範例3
public Class Car{}
則default constructor為:
public Class Car{ public Car(String s){ super(); } }
注意!雖然super()是compiler自動加入,但如果這個時候superclass並沒有不帶parameters的constructor,則compiler會失敗,告知沒有default constructor available for Car。
最後謹記,constructor是不能被override(因為不是method,只有method可以被extend+override),但constructor是可以被overload的。
Overloading Constructor
假如Bike的overloading constructor寫法如下:
則當new Car()時,Job stack如下:
public class Car{ int gear; int cadence; public Car(int gear, int cadence) {//這邊才會呼叫superclass的constructor
this.gear = gear; this.cadence = cadence; } public Car() { this(giveAnInt(), 1); } static int giveAnInt(){//這邊一定要用static,因為superclass costructor還沒被執行完畢 return 1; } }
則當new Car()時,Job stack如下:
|--------------------------------
|4. Object()
|---------------------------------
|3. Bike(int, int) call super()
|---------------------------------
|2. Car() call this(int, int)
|---------------------------------
|1. Main call new Car()
|---------------------------------
- 這個呼叫overloading constructor的方式是使用關鍵字this,但就把它當成一個method來使用,所以用this()來呼叫它。
- 注意giveAnInt()在Car()內第一行呼叫的時候一定要用static,因為此時superclass constructor還沒有被執行完畢,所以不能使用class內的instance(not static) method或是存取一個instance variable。
- constructor內呼叫this()只是拖延那件必然會發生的事(呼叫superclass的constructor)。某個地方,某個constructor子必須呼叫 super()(此範例為Car(int, int)。
Critical rule: constructor的第一行一定要是super()或this(),也代表一個constructor永遠不能呼叫 super()又呼叫 this()
- 如果第一行沒有super()或this(),那麼compiler會幫忙插入super()
ㄧ以上這段將造成recursive
結論:
擁有overloading constructor的好處是可以提供彈性的方式,讓程式碼可以透過不同管道initial object,而一個constructor呼叫另一個constructor的好處是,避免程式碼的重複。想像一個情境,你認為customer class要被實體化前一定要提供客戶姓名電話地址,但如果今天就是有客戶不提供電話地址,那麼你可以有一個constructor來處理這樣的案子
public Customer(String name){
//初始化default電話地址
Customer(name, tel, addr);
}
然後再將這些初始化後的電話地址帶入原本預期的constructor
public Customer(String name, String tel, String addr){//真正該做的事情}
這樣的互相呼叫方式,可以避免將真正該做的事情也寫到只提供name的constructor內,避免程式碼的重複。
- 這個呼叫overloading constructor的方式是使用關鍵字this,但就把它當成一個method來使用,所以用this()來呼叫它。
- 注意giveAnInt()在Car()內第一行呼叫的時候一定要用static,因為此時superclass constructor還沒有被執行完畢,所以不能使用class內的instance(not static) method或是存取一個instance variable。
- constructor內呼叫this()只是拖延那件必然會發生的事(呼叫superclass的constructor)。某個地方,某個constructor子必須呼叫 super()(此範例為Car(int, int)。
Critical rule: constructor的第一行一定要是super()或this(),也代表一個constructor永遠不能呼叫 super()又呼叫 this()
- 如果第一行沒有super()或this(),那麼compiler會幫忙插入super()
public Car(int gear, int cadence) { this(); this.gear = gear; this.cadence = cadence; } public Car() { this(10, 3); }
結論:
擁有overloading constructor的好處是可以提供彈性的方式,讓程式碼可以透過不同管道initial object,而一個constructor呼叫另一個constructor的好處是,避免程式碼的重複。想像一個情境,你認為customer class要被實體化前一定要提供客戶姓名電話地址,但如果今天就是有客戶不提供電話地址,那麼你可以有一個constructor來處理這樣的案子
public Customer(String name){
//初始化default電話地址
Customer(name, tel, addr);
}
然後再將這些初始化後的電話地址帶入原本預期的constructor
public Customer(String name, String tel, String addr){//真正該做的事情}
這樣的互相呼叫方式,可以避免將真正該做的事情也寫到只提供name的constructor內,避免程式碼的重複。
沒有留言:
張貼留言