顯示具有 過載 標籤的文章。 顯示所有文章
顯示具有 過載 標籤的文章。 顯示所有文章

2021年7月13日 星期二

JAVA 物件導向的概念-13 複習模糊化寫法、過載特性,多型

   在看多型章節時發現多型和模糊化寫法、過載有相似之處,故決定開頭先複習,再介紹多型。

  先複習模糊化寫法,在兩個類別是繼承關係時,我們可以使用模糊化寫法宣告物件,例如父類別是人類 Human,其中一個子類別是騎士 Kinght,我們宣告藍斯洛特是騎士時,可以寫作

Kinght lancelot = new Kinght();// 明確宣告藍斯洛特為一個騎士,口語說法:騎士藍斯洛特是一個騎士。

;可以寫作

Human lancelot = new Kinght();// 模糊宣告藍斯洛特為一個騎士,口語說法:人類藍斯洛特是一個騎士。

,上面這一行就是模糊化寫法,等號左邊只說了藍斯洛是人類,右邊才宣告了他是騎士;除此之外還可以寫作

var lancelot = new Kinght();

。無論上面哪一種寫法所產生出來的物件,都可以使用子類別中的方法,只是模糊寫法的物件在使用子類別的方法時,該物件必須強制轉型。

  再來是過載特性的複習,在一個類別中,有複數個成員方法的名稱相同,但其需要的參數屬性或數量的不同,JAVA 可以自動依所傳的參數判斷要使用哪一個方法,這個特性稱之為過載。

  JAVA 多型正是用到了模糊化寫法,而且擁有過載的特性。

  宣告一個父類別,父類別中擁有它自己的方法,然後其子類別中也有同名的方法,覆寫掉父類別中的同名方法;在主程式中定義的方法指定丟入參數為父類別的物件,但實際上你可以丟入任何有繼承該父類別的子類別所產生的物件,這就是模糊化;而 JAVA 會自動使用該物件在子類別中的同名方法,這就是過載。以下是 Elton 教我多型概念時的範例。

父類別:Shape 形狀,包含了一個它自己的方法 area 面積;

public class Shape {
public double area() {
return 0;
}
}

子類別:Circle 圓形,包含了和父類別同名的方法 area 面積;

public class Circle extends Shape {
int r;
double pi = 3.1415926;

public int getR() {
return r;
}

public void setR(int r) {
this.r = r;
}

public double getPi() {
return pi;
}

public void setPi(double pi) {
this.pi = pi;
}

public double area() {
return pi*r*r;
}

}

子類別:Rectangle 矩形,包含了和父類別同名的方法 area 面積;

public class Rectangle extends Shape {
int length;
int width;

public int getLength() {
return length;
}

public void setLength(int length) {
this.length = length;
}

public int getWidth() {
return width;
}

public void setWidth(int width) {
this.width = width;
}

public double area() {
return length * width;
}

}

主程式:裡面示範了方法的過載和多型兩種方式,註解應該算詳細,所以這裡不再說明。

public class Main {

// 以下是方法的多載(overloading),方法名稱相同,會依傳入的參數型別或數量不同而區別使用哪一方法。
// 萬一今天有多個不同的形狀,例如三角形,梯形,六角形等。下方就要為特定的形狀再多加宣告多組的面積方法,有些繁瑣。
public static double calArea(Circle cir) {
return cir.area();
}

public static double calArea(Rectangle rec) {
return rec.area();
}

// 那麼為了有更簡潔的方式,我們可以使用到多型的觀念。只宣告一組面積方法來算所有形狀的面積。
// 設定承接物件為父類別,模糊化所承接之物。
public static double calAreaBetter(Shape sha) {
return sha.area();
}

public static void main(String[] args) {
Circle cir1 = new Circle();
cir1.setR(12);

Rectangle rec1 = new Rectangle();
rec1.setLength(5);
rec1.setWidth(10);

double cirArea = calArea(cir1);
double recArea = calArea(rec1);
System.out.println("this is an area of circle by cir method:" + cirArea);
System.out.println("this is an area of rectangle by rec method:" + recArea);

cirArea = calAreaBetter(cir1);
recArea = calAreaBetter(rec1);
System.out.println("this is an area of circle by better method:" + cirArea);
System.out.println("this is an area of rectangle by better method:" + recArea);
}
}

結果:不管是用方法的過載或是多型的概念,都得到同樣的面積值。

this is an area of circle by cir method:452.38933440000005
this is an area of rectangle by rec method:50.0
this is an area of circle by better method:452.38933440000005
this is an area of rectangle by better method:50.0

Process finished with exit code 0

這個範例中的父類別是一般的類別,但我買的書,其範例是用抽象類別當父類別,或是用介面讓不同的類別實作,來完成多型的目的,其使用是自由自在的,下一篇會再練習一次多型,應該也是最後一篇物件導向的概念文章了,之後會練習如何使用套件與檔案處理。


2021年6月28日 星期一

JAVA 物件導向的概念-11 覆寫、隱藏父類別中的方法,過載

  本篇故事:愛未未在逃亡的過程中,見證到太多無辜的女人被汙衊為魔女而遭到殺害,這一切逼使著她投入黑暗,於是暗黑愛未未出現了! 她要復仇!

  這一篇要練習的覆寫和隱藏父類別的方法,前陣子很紅的廣告詞:開局就送魔關羽!有魔關羽就有一般的關羽,他們一定極為相似,魔關羽繼承了關羽的大部份屬性,也一定有所不同,魔關羽的技能可能更帶有邪氣!

  本篇我所做的就是使者與暗黑使者兩個類別,其中暗黑使者類別繼承了使者類別,同時修改(隱藏或覆寫)了它所繼承的方法,只要子類別內的方法和父類別內的方法同名、同參數列、同回傳值形態,就會修改!之所以要都相同,理由之一是因為 JAVA 還有一個功能叫過載,即使方法名稱相同,只要傳入的參數不同,JAVA 會自動選擇適合的方法。過戴會在本篇最下方再介紹一次。

父類別:

/* 使者類別 */
// 編寫人:Lancelot Cheng
public class Envoy {
public String name, brithday, blood;
public String profession, weapon;
public int level, exp, oID;
//private Contract envoyDemon;

// 建構子
public Envoy (int oID, String nn, String bD, String bb,
String pro, int lev, int ex, String wea) {
name = nn;
brithday = bD;
blood = bb;
this.oID = oID;
profession = pro;
level = lev;
exp = ex;
weapon = wea;
}

public static void surrender(){
System.out.println("投降");
}

public void normalattack () {
System.out.println( weapon + "一般攻擊!");
}
}

子類別:注意這裡有兩個方法的名稱與父類別相同,同內容不同,此即為修改。

/* 暗黑使者類別 */
// 編寫人:Lancelot Cheng
public class DarkEnvoy extends Envoy{

public DarkEnvoy(int oID, String nn, String bD, String bb
, String pro, int lev, int ex, String wea) {
super(oID, nn, bD, bb, pro, lev, ex, wea);
}

public static void surrender(){ // 與父類別同名:隱藏
System.out.println("自爆!");
}

public void attack () { // 與父類別同名:覆寫
System.out.println(weapon + "暗黑屬性攻擊!");
}
}

主程式:創造了一個愛未未使者和暗黑愛未未使者,都用它們的方法。

/* 主程式 */
// 編寫人:Lancelot Cheng
public class Main {
public static void main( String[] args){

// 創造一個愛未未使者物件。
Envoy ai = new Envoy( 0, "愛未未", "0712", "AB",
"魔術師", 10, 200, "撲克牌");

System.out.print("愛未未攻擊:");
ai.normalattack();
System.out.print("愛未未投降:");
ai.surrender();

System.out.println();

// 創造一個暗黑愛未未使者物件。
DarkEnvoy darkAi = new DarkEnvoy(0, "愛未未", "0712", "AB",
"魔術師", 10, 200, "撲克牌");

System.out.print("暗黑愛未未攻擊:");
darkAi.attack();
System.out.print("暗黑愛未未投降:");
darkAi.surrender();
}
}

結果:兩個物件的方法名稱相同,但結果不同,意思是子類別內的方法的確修改了。

愛未未攻擊:撲克牌一般攻擊!
愛未未投降:投降

暗黑愛未未攻擊:撲克牌暗黑屬性攻擊!
暗黑愛未未投降:自爆!

Process finished with exit code 0


  這個練習滿簡單的,但不是一個好的寫法,我認為最好的寫法是使者類別與暗黑使者類別有共同的父類別,因為最好物件都是由子類產生,原因是子類別只能繼承到父類別中公開的變數,於是裡面所有的變數都必須設為公開,造成的結果是父類別所產生的物件,其成員可以被任意讀取與更動。都是修改方法,為什麼一個叫隱藏一個叫覆寫,我不知道原因。

  關於過載,在同一個類別中,定義同名的方法,當你在使用該類別產生的物件之方法時, JAVA 可以以你輸入的參數類型、數量判斷要用哪一個方法。舉個應用的例子,我們要計算三角形面積,依照所拿到的條件是邊長、邊長、邊長或角度、邊長、角度還是邊長、角度、邊長,會用使用不同的方法,但這些方法的目的都相同,就是算出面積,對我們來說,因為方法不同而去記憶不同的方法名字很麻煩,所以名字都取一樣,讓 JAVA 依輸入參數屬性幫我們判斷使用哪個方法就好,這就是過載。其中輸入的參數也可以是我們自己定義的物件。在這邊的算三角形面積例子有點不太好,因為角度、邊長都可以是浮點數。

  之後會再介紹介面與抽象類別,期待下一次的惡魔使者愛未未。