2017年11月5日 星期日

Day2-8 Constructor and Instantiation 建構子與實體化

1.6 Given a set of classes and superclasses, develop constructors for one or more of the classes. Given a class declaration, determine if a default constructor will be created, and if so, determine the behavior of that constructor. Given a nested or non-nested class listing, write code to instantiate the class. 
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() {}
}
constructor兩個建立重點
  1. 名稱必須和class相同
  2. 沒有return type
  3. 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的時候發生了以下幾項事件:

  1. Bike的constructor被呼叫,並暗中執行super()以呼叫所有superclass的constructor,除非bike的constructor呼叫overload的constructor
  2. Car的constructor被呼叫
  3. Object的constructor被呼叫
  4. Object的instance variable被給了explicit values(明確值)。如x=1,1是x的explicit value
  5. 完成Object的constructor
  6. Car的instance variable被給了explicit values(if exists)
  7. 完成Car的constructor
  8. Bike的instance variable被給了explicit values(if exists)
  9. 完成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的樣子
  1. access modifier和class的相同
  2. 沒有parameters
  3. 以不帶arguments的方式呼叫superclass的constructor(super())
  • 範例1
Class Car{}

則default constructor為:

Class Car{
    Car(){
        super();
    }
}

注意constructor的access modifier也是default,和class一樣

  • 範例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();
    }
}

compiler還是會建立不帶parameters的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寫法如下:

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()

public Car(int gear, int cadence) {
 this();
 this.gear = gear;
 this.cadence = cadence;
}
public Car() {
 this(10, 3);
}
ㄧ以上這段將造成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內,避免程式碼的重複

沒有留言:

張貼留言