2017年11月4日 星期六

Day2-4 Override and Overload 覆寫及多載

1.5 Given a code example, determine if a method is correctly overriding or overloading another method, and identify legal return values (including covariant returns), for the method.
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. 


Overriding method(覆寫函式)

class Animal {
   public void move() {
      System.out.println("Animals can move");
   }
}

class Dog extends Animal {
   public void move() {
      System.out.println("Dogs can walk and run");
   }
}
上述範例中Dog override move(),針對非abstract class可以選擇要不要override,但是如果superclass有abstract class,則一定要override,除非該subclass也是abstract class。否則若是concrete class則一定需要override。

以下為一polymorphism範例
public class TestDog {

   public static void main(String args[]) {
      Animal a = new Animal();   // Animal reference and object
      Animal b = new Dog();   // Animal reference but Dog object

      a.move();   // runs the method in Animal class
      b.move();   // runs the method in Dog class
   }
}
- 編譯器只允許呼叫reference variable type內擁有的method。polymorphism的功能在於,可以使用superclass的variable reference,指到subclass的object,甚至使用被override的method。
- 如上節所說,JVM會去呼叫該object的真實型別看看method有沒有被override,若有,就會使用。
- overriding method不能擁有比原method更侷限的access modifier (ex: public -> protected)
說個故事:有一天電器Class(Appliances Class)宣稱可以藉由extends該Class取得賣出價格method(sellPrice()),但今天冰箱(Refrigerator Class) extends 後把sellPrice()繼承了而且偷改access modifier變成private,則以下範例將會有問題:
Appliances rg = new Refrigerator(); //object type: Refrigerator, reference type: Appliances

rg.sellPrice();   // runs the method in Refrigerator class 此行會爆炸
- 讓superclass的reference variable可以指到subclass object的原因是,subclass可以保證能夠做得到所以superclass能夠做到的事情
- 為了達到不管reference variable今天指到的object type是何者,都要能夠保證能夠使用原本reference variable type可以呼叫的method,因此有以下幾點規範
  1. overriding method不能擁有比original method更侷限的access modifier,但可以更鬆散
  2. overriding method的parameters必須和original method的相同,如果不同就不叫做overriding,只是寫了一個新的method
  3. overriding method的return type必須和original method的相同,或者是subtype (covariant return)
  4. 只有當instance method有被subclass extends的時候才可以做overriding。意即,一個private,final,static的method都不能夠被overriding
  5. 不論original method是否有宣告exception,overriding method可以拋出runtime exception(unchecked exception)
  6. overriding method不能夠拋出新的checked exception,異常範圍也不可以更廣
  7. 不論original method宣告了些異常,overriding method不需要宣告任何它不會拋出的exception。
  8. 不能override final or static method
- 若想要在override之前先執行original method做的事情,則需要用到keyword(super)
public class FlyingCar extends Car{

   public int startEngine(EncryptedKey key) {
      super.startEngine();//先執行super class Car裡面的startEngine method
      //繼續做FlyingCar想ㄧ做的事情
   }
}
- super keyword只能用在instance method上(非final,static)

Overload method(多載函式)

- 使用overload的時機:程式碼需要考慮更多有可能傳入的參數,但呼叫者不需要強迫呼叫另外一個名字不相同的method name。
- Overload規則如下:
  • 必須變更parameter
  • 可以變更return type
  • 可以變更access modifier
  • 可以宣告新的或範圍更廣的checked exception
  • 可以在subclass和superclass間發生。例如superclass的method: getHeight();而subclass繼承後不改寫superClass的getHeight(),另外寫了一個method: getHeight(int years),這樣也叫做overload

呼叫Overloading method


class TestAnimal
{
    public void doStuff(Animal am){
        System.out.println("Animal");
    }

    public void doStuff(Cat cat){
        System.out.println("Cat");
    }

    public static void main (String args [])
    {
        TestAnimal ta = new TestAnimal();
        Animal am = new Animal();
        Animal cat = new Cat();
        ta.doStuff(am); //print "Animal"
        ta.doStuff(cat); //print "Cat"
    }
}

注意上述範例,最後ta.doStuff(cat)執行的是public void doStuff(Cat cat)這個method!
在runtime時雖然知道了這個object的真實type,並不會再runtime的時候被動態的決定要呼叫哪個overloading method。
總結
  • override: 根據runtime時的object type決定要執行哪一個method。
  • overload: 根據compile時被傳入當作overloading method內argument的variable reference type來決定的。

Override and Overload

Polymorphism並不會影響哪個override的method會被呼叫。Method可以同時被Overload及Override,如下面的範例:


class Animal{
    void eat(){
        System.out.println("Animal eats");
    }
}
class Cat extends Animal{
    void eat(){
        System.out.println("Cat eats");
    }
    void eat(String mood){
        System.out.println("Cat has mood of eat : " + mood);
    }
}

class TestAnimal{
    public static void main (String args []){
        Animal a = new Animal();
        a.eat(); //print "Animal eats"

        Cat c = new Cat();
        c.eat(); //print "Cat eats"

        Animal am = new Cat();
        am.eat(); //print "Cat eats"

        Cat ct = new Cat();
        ct.eat("Happy"); //print "Cat has mood of eat : Happy"

        Animal am2 = new Animal();
        am2.eat("Excited"); //Compile error! Animal內沒有argument為String的eat method

        Animal am3 = new Cat();
        am3.eat("Sad"); //Compile error! 雖然此行是根據reference type(Cat)來決定要跑的method,但因為Animal沒有此method,所以編譯會直接錯誤
    }
}

注意每個Output。

沒有留言:

張貼留言