polymorphism & Abstract Class

21 April 2020

OOP - polymorphism & Abstract class

讓derived class的methods changes apply到base class的method changes 利用late-binding給予一個method多種執行方法、意義

簡單來說就是為了Flexibility, base class可以有method, derived class能夠依據狀況把method的內容複寫
目的在於在開發時常常有物件應該屬於同類但因為些微的差距所以method要有調整,polymorphism就是在這種狀況下derived class能覆寫那些method符合自己的需求

Reference: medium

情境

定義一個base class跟一些共用method,但是之後又加了一個derived class C,而C其中繼承到的一個method A呼叫了C override的method B,但是method B本身是base class的method所以會隨著base class先compiled了,那Class C呼叫method A時很有可能錯誤,因為method B沒有隨著新的Class定義的method B而作出對應修改。

Late binding

late binding = dynamic binding

binding

某method的程式碼內呼叫其他method。
假設method是在compile時就跟呼叫的method做好連接 : early binding
假設method是在run time在跟呼叫的method做好連接 : late binding
Java幾乎都使用late binding,因此method A在呼叫method B時,是真的要呼叫時才做連接,不是編譯時就做連接
因此在object編譯好後,會有像dynamic link的感覺有記錄某個method要連到哪。

final

final method表示此method不能被override
final class代表該class不能當作base class

public final void someMethod(){} public final class someclass{}

宣告final的method或class可以用early binding,因為derived class也沒有機會改寫,增加compiler效率

toString polymorphism

所有的class都屬於object class,object class有自己的toString method, 因此在System.out.println(a)時都可以印出String,因為object class有定義好
但在我們自創的class中,我們可以自己寫一個toString的class,這樣System.out.println呼叫object toString時,會呼叫到自己定義的class(descendant class)的toString而不是呼叫object class的toString

no late binding

  1. final method
  2. private method
  3. static method
static method可以想像,因為static method不論多少object都只有一個,就是定義在base 
class那個,每個object共用,問題在於如果static method呼叫了某個polymorphism的method
A,則method A會以base class的method A為主(static method所在的class,畢竟是以呼叫
該method的class: base class)而不是derived class

upcasting, downcasting

upcasting 子類別 type cast成父類別 downcasting 父類別 type cast成子類別

downcasting

downcasting很容易有error,因為子類別很多時候會有自己才有的variable,這時候downcast就會error,因此使用時要確保沒有這些事情發生才用downcast

B extends A  A為B的父類別且B有一些A沒有的instance variable
A = (B)A -> run-time error
A = B -> compile error

instanceof

可以用instanceof來確定downcast能不能做(確定是不是同個class),同個class才能做

Object instanceof Class_name

Clone

每個自己定義的class都會從Object class繼承clone這個method,只是要自己override,就是做deep copy複製一份依樣的object。

protected Object clone()
----------------------- override
public Sale clone(){...(可以先用new, constructor的方式)} 
把protected改成public,外面人才能呼叫

小注意

java 5.0以前的版本override不允許換return 的type,所以如果用以前的java版本來做clone完後要記得type cast成現在定義的class,java 5.0後也有可能出現這個問題(可能別人定義的clone沒改type)
所以最好方式是自己呼叫clone後在type cast一次保險

Sale copysale = (Sale)s.clone();

Copy constructor & clone差別 ???

要複製一個新的object,尤其在牽扯到父、子類別、polymorphism時要特別注意,盡量用clone。
我們知道子類別算是父類別的class,所以宣告是父類別為參數的函式可以傳子類別進去,如果複製時是用copy constructor,那就只會複製到該子類別object屬於父類別的部分,自己獨有的不會複製到,那這樣否些情況是不好的,如下:

Class : Sales->DiscountSale
a : DiscountSale
b : sale
public static Sale badcopy(Sale a){
    Sale b = new Sale(a);    // 此時身為object a獨有的東西不會複製給b
    return b;                // 假設a傳進去時是derived class DiscountSale
                            // 此時用copy constructor的話會呼叫Sale的constructor
                            // 而sale是base class,所以等於原本object a獨有的東西
                            // 就不會複製給b(因為是呼叫base class constructor)
                            // constructor當然不會定義derive class獨有東西的assign
}

public static Sale goodcopy(Sale a){
    Sale b = a.clone();    // 此時身為object a獨有的東西才會複製給b
                           // 因為clone可以override,所以此時呼叫的clone是呼叫
                           // derive class的method,而不是呼叫到base class
                           // 的constructor,所以clone內部function可以把derive
                           // class獨有的東西傳給b。
    return b;
}

Abstract class

沒有完整defined的class,不能create object,但可以用它來當作base class定義一些derived class,會定義一些abstract method。可以想成abstract class就是一種object type但是不能夠產生object, instance。

子類別要完整實做這些abstract method

  1. abstract method就是要給derived class實作,所以不能宣告private
  2. 沒有實做完abstract method的derived class也是abstract class,不能建立object
public abstract class AbstractCircle {
    protected double radius;

    public void setRedius(int radius) { this.radius = radius; }
    public double getRadius() { return radius; }

    public abstract void render();
}