[Java] 6.4. 多型

多型,繼承下物件的多種型別。

 

image/svg+xml繼承,讓程式設計師、測試⼈員或美⼯⼈員皆是 “IS-A” 員⼯ 轉型,並不會改變改寫的事實 6.4. 多型 - Polymorphism class Person { // 略過⼀些屬性與⽅法 } class Employee extends Person { // 略過⼀些屬性與⽅法 double getBonus (){ return ( 0.1 * salary); } } class Tester extends Employee { void test (){ System.out.println( " " + name + " 正在測試系統 " ); System.out.println( "Testing By" + name); System.out.println( " " + name + " 終於測試完了 " ); } } class Programmer extends Employee { void code (){ System.out.println( " " + name + " 正在寫程式 " ); System.out.println( "Coding By" + name); System.out.println( " " + name + " 終於寫完程式了 " ); } void debug (){ System.out.println( " " + name + " 正在除錯 " ); System.out.println( "Debugging By" + name); System.out.println( " " + name + " 終於抓出蟲了 " ); } } class Artist extends Employee { void draw (){ System.out.println( " " + name + " 正在畫圖畫 " ); System.out.println( "Drawing By" + name); System.out.println( " " + name + " 終於畫完了 " ); } } class Programmer extends Employee { // 略過⼀些程式 void show (){ System.out.println( " 我是程式設計師 " ); super .show(); } double getBonus (){ return salary * 3 ; } } class Tester extends Employee { // 略過⼀些程式 void show (){ System.out.println( " 我是測試⼈員 " ); super .show(); } double getBonus (){ return salary * 1.5 ; } } class Artist extends Employee { // 略過⼀些程式 void show (){ System.out.println( " 我是美⼯⼈員 " ); super .show(); } double getBonus (){ return salary * 2 ; } } class Main { public static void main( String [] args){ Programmer p = new Programmer (); Tester t = new Tester (); Artist a = new Artist (); p.salary = 30000 ; t.salary = 30000 ; a.salary = 30000 ; System.out.println( p.getBonus ()); System.out.println( t.getBonus ()); System.out.println( a.getBonus ()); } } 執⾏結果 90000 45000 60000 class Main { public static void main( String [] args){ Tester t = new Tester (); Artist a = new Artist (); Programmer p = new Programmer (); } } class Main { public static void main( String [] args){ Programmer p = new Programmer (); Tester t = new Tester (); Artist a = new Artist (); p.name = "Jack" ; p.name = "Eric" ; p.name = "Marry" ; Employee e1 = p ; Employee e2 = t ; Employee e3 = a ; } } class Main { public static void main( String [] args){ Programmer p = new Programmer (); Tester t = new Tester (); Artist a = new Artist (); p.name = "Jack" ; p.name = "Eric" ; p.name = "Marry" ; Employee e1 = p ; Employee e2 = t ; Employee e3 = a ; e1 . code (); e2 . test (); e3 . draw (); } } 編譯時發⽣錯誤 Main.java:15: error: cannot find symbol e1.code(); ^ symbol: method code() location: variable e1 of type Employee Main.java:16: error: cannot find symbol e2.test(); ^ symbol: method test() location: variable e2 of type Employee Main.java:17: error: cannot find symbol e3.draw(); ^ symbol: method draw() location: variable e3 of type Employee 3 errors class Main { public static void main( String [] args){ Programmer p = new Programmer (); p.id = "k123456789" ; p.name = "jack" ; p.gender = " 男⽣ " ; p.setAge( 25 ); p.employeeID = "048679" ; p.salary = 40000 ; Employee e = p ; Programmer p1 = (Programmer) e ; p1 . code (); p1 . debug (); } } class Main { public static void main( String [] args){ Programmer p = new Programmer (); p.id = "k123456789" ; p.name = "jack" ; p.gender = " 男⽣ " ; p.setAge( 25 ); p.employeeID = "048679" ; p.salary = 40000 ; Employee e = p ; e . show (); } } 執⾏結果 我是程式設計⼈員 我的⾝份證字號是 k1234567890 姓名是 jack 性別是男⽣ 年齡是 25 員⼯編號是 048679 薪資是 40000 class Boss { void payBonus ( Employee [] employees ){ for ( Employee e : employees ) System.out.println( 員⼯ + e.name + ", 得到獎⾦ " + e . getBonus ()); } } class Main { public static void main( String [] args){ Programmer p = new Programmer (); Tester t = new Tester (); Artist a = new Artist (); p.name = "Jack" ; p.salary = 40000 ; t.name = "Eric" ; t.salary = 40000 ; a.name = "Sala" ; a.salary = 40000 ; Employee [] allEmployees = { p , t , a }; Boss b = new Boss (); b . payBonus ( allEmployees ); } } 執⾏結果 120000    60000     80000     class Person { // 略過⼀些程式 String name ; // 略過⼀些程式 } class Employee extends Person { String employeeID; int salary; String name ; // 略過⼀些程式 } class Main { public static void main( String [] args){ Employee e = new Employee (); e . name = " jack " ; Person p = e ; p . name = " jack wallence " ; System.out.println( e . name ); System.out.println( p . name ); } } 執⾏結果 jack jack wallence J6_4_1 – Person.java 1. 程式設計師( Programmer )繼承⾃員⼯類別( Employee )。 J6_4_2 – Ar 4 st.java J6_4_1 – Employee.java J6_4_1 – Tester.java 1. 在此有個⼈員類別( Person )。 2. 這是員⼯類別( Employee )其繼承⾃⼈員類別。 3. 為員⼯加上獎⾦額度⽅法 getBonus() )。預設是薪⽔的 10% 4. 測試⼈員類別( Tester ),其擴充⾃員⼯類別。 5. 測試⽅法( test() )。 J6_4_1 – Programmer.java 6. 程式設計師類別( Programmer ),其是員⼯的⼀種。 7. 寫程式⽅法( code() )。 7. 除錯⽅法( debug() )。 J6_4_1 – Ar 4 st.java 9. 美⼯⼈員類別( Artist ),其也是擴充⾃員⼯類別。 10. 繪圖⽅法( draw() )。 J6_4_2 – Programmer.java 2. 為程式設計師所寫⾃我介紹⽅法 show() ),表明是程式設計師的⾝份。 3. 改寫獎⾦額度⽅法( getBonus() ), 3 倍薪資滿⾜程式設計師應得的獎⾦。 4. 測試⼈員( Tester )繼承⾃員⼯類別。 J6_4_2 – Tester.java 5. 為測試⼈員所寫⾃我介紹⽅法 show() ),表明為測試⼈員的⾝份。 6. 改寫獎⾦額度⽅法( getBonus() ), 1.5 倍作薪資作為測試⼈員應得的獎⾦。 7. 美⼯⼈員( Artist )繼承⾃員⼯類別。 8. 為美⼯⼈員所寫⾃我介紹⽅法 show() ),表明為美⼯⼈員的⾝份。 9. 改寫獎⾦額度⽅法( getBonus() ), 2 倍薪資作為美⼯⼈員應得的獎⾦。 J6_4_2 – Main.java 當然您也可以測試⼀下每個⾓⾊的⾃我介紹⽅法( show() )以驗證改寫是否 有成功。 J6_4_3 – Main.java 10. 分別建立程式設計師、測試⼈員與美⼯⼈員 的物件,並將所有⼈員的薪資統⼀設為 30000 11. 不同⾓⾊的物件,因為獎⾦額度的比率不同,因此在薪資 salary )相同的情況下,還是會取得不同的獎⾦額度的。 1. 這是測試⼈員物件( Tester )其有多重⾝份,測試⼈物件 “IS-A” 員⼯物件 Employee ),且 “IS-A” ⼈員物件( Person )。⽽ “IS-A” 即有 是⼀個 的意思在。 3. 這是程式設計師物件( Programmer )。程式設計 師物件 “IS-A” 員⼯物件,且 “IS-A” ⼈員物件。 J6_4_4 – Main.java 1. 建立了程式設計⼈員、測試⼈員或是美⼯設計師的 物件( Programmer Tester Artist )。 2. 不論是程式設計⼈員、測試⼈員或是美⼯設計 師,都是可以視為員⼯物件並放入員⼯型別的變數中 保存,⽽不論是程式設計⼈員、測試⼈員或是美⼯設 計師都因為繼承⾃員⼯類別,因此可⾃動的向上轉型 為員⼯型別的物件,在存入員⼯型別的變數中。 3. 還記得變數前⽅型別的作⽤吧。沒錯,就是要限制 變數中所裝的東⻄。因此若是員⼯型別( Employee 則這個變數就只可裝下員⼯型別的物件。 (Employee) p (Employee) p (Employee) p 4. 向上轉型的意思,即是往⽗類別 的⽅向轉型。每⼀個⼦類別只會有⼀ 個直接繼承的⽗類別,因此可以⾃動 轉型為⽗類型的型別。 J6_4_5 – Main.java 1. 建立了程式設計⼈員、測試⼈員或是美⼯設計師 的物件( Programmer Tester Artist )。 2. 不論是程式設計⼈員、測試⼈員或是美⼯設計 師的物件,皆可放入員⼯型別的變數中保存,以轉 型為員⼯型別的物件。 3. 當您嘗試著將已經視為員⼯看待的程式度計師,命令他 進⾏寫程式( Code() )的⽅法時,這時會發⽣錯誤。原因 就出在員⼯類別上並沒有寫程式⽅法可以使⽤。當物件的型 別轉換為員⼯型別時,就必須⽤員⼯的⾓度來看這個物件。 同樣的,只員⼯型別呼叫測試⽅法( test() )或繪圖⽅法 drwa() )也是會出現編譯錯誤的。同樣的道理,當物件 轉換為員⼯型別時,就必須⽤員⼯的⾓度來看這個物件。 J6_4_6 – Main.java 1. 建立⼀個程式設計師型別的物件( Programmer )。 4. 這位⼈員最後變回了程式⼈員的⾝份,並保存 p1 變數中,同時他也恢復了執⾏寫程式 Code() )與除錯( Debug() )⽅法的能⼒。 2. 先轉型為員⼯型別( Employee )的物件,並放物 e 變數中。這部份是會⾃動轉型的,因為程式設計師類 別是繼承⾃員⼯類別,因此也擁有員⼯類別的型別。   3. 使⽤向下轉型(即強迫轉型)將員⼯物件強迫轉 型為程式設計師型別的物件。並放入 p1 變數中。 5. 向下轉型的意思,即是往⼦類 別的⽅向轉型。每⼀個⽗類別可能 有多個繼承的⼦類別,因此必須透 過強迫轉型,明確的指定轉換的型 別,才能轉型為⽗類別的型別。 J6_4_7 – Main.java 1. 建立⼀個程式設計師型別的物件( Programmer )。 2. 將程式⼈員的物件放入員⼯型別的 e 變數 當中,以將程式⼈員視為⼀個員⼯來看待。 3. 進⾏⾃我介紹時還是會保有原本程式⼈員的⾃我介紹 show() ),在第 1 ⾏表明 我是程式設計⼈員 的⾝份,轉 型為員⼯後,並不會改變此員⼯就是程式設計⼈員的事實。 J6_4_8 – Boss.java 1. 這是老闆類別( Boss ),它的發放獎⾦⽅法 payBonus() )會對代入的員⼯發放獎⾦。 2. 這是發放獎⾦⽅法( payBonus() ),特別的是其參數 是員⼯型別的陣列參數,代表即將代入員⼯,以發放獎⾦。 3. 透過 for ,依序的取出每個員⼯物件,並呼叫員⼯的發 收獎⾦⽅法( getBonus() )⽅法,取得每位員⼯的獎⾦。 J6_4_8 – Main.java 4. 分別建立不同⾓⾊的員⼯,並設定其基本薪資。 6. 建立老闆物件,並對所有員⼯發放獎⾦。最後老闆仍是會照員 ⼯原始的⾝份去發放獎⾦,再次證套轉型並不會改變改寫的事實。 5. 將程式設計師、測試⼈員與美⼯⼈員的物件,都轉 型為員⼯物件後放入員⼯陣列 -allEmployees 中。 J6_4_9 – Person.java J6_4_9 – Employee.java J6_4_9 – Main.java 1. 這是⼈員類別( Person ),其中有個姓名屬性( name )。 2. 這是員⼯類別( Employee ),其繼承⾃⼈員類別。 3. 重複宣告⼀個姓名屬性( name )。這時 會遮蓋原有的繼承⾃⼈員類別的姓名屬性。 4. 建立員⼯物件,並放入⾄員⼯型別的變數 e 中。 5. 這時的名稱屬性( name )是員⼯類別 新宣告的名稱屬性,在此設定為 “jack” 6. 轉型為⼈員型別的物件,並放入 p 變數中。 8. 雖然是同⼀個物件,但因為名稱屬性是位於不同的空間中(⼀個在員⼯物件上, 另⼀個在⼈員物件上),因此這兩個名稱屬性皆可以保存不同的姓名資訊,在此關鍵 為變數的型別,決定了從哪個型別操作物件, e 變數為員⼯型別,因此可存取到員⼯ 物件上的姓名屬性,⽽ p 變數為⼈員型別,因此存取的是⼈員物件上的姓名屬性。 7. 這時的名稱屬性( name )是⼈員類別的名稱 屬性,在此設定為 “jack   wallence” 讓員⼯的⾓⾊更多樣化 ? 改寫,改變⾃我介紹與獎⾦額度⽅法 1 2 3 1 2 3 向上轉型,以員⼯型別的⾓度看待每⼀位員⼯ 切記,轉型成員⼯就必須以員⼯的⾝份來對待 1 2 3 1 2 3 向下轉型,表明⼈員的真實⾝份 1 1 老闆發放獎⾦,再次證明改寫不變的事實 轉型 vs 遮蓋屬性,型別決定屬性的使⽤範圍 1 1 1 2 1 2 IS-A IS-A IS-A 2. 這是美⼯⼈員物件( Artist )。美⼯⼈員 物件 “IS-A” 員⼯物件,且 “IS-A” ⼈員物件。

留言