430 likes | 527 Views
陣列. 陣列與多型. 借用上一章中, Worker 、 HourlyWorker 以及 SalaryWorker 的範例來說明多型應用於陣列的情形。 公司內有些員工是 SalaryWorker ,有些是 HourlyWorker 。. Worker[] w = new Worker[5];. if(choice.equals("h")) { number = JOptionPane.showInputDialog(" 輸入工作時數 "); w[i] = new HourlyWorker(name, Integer.parseInt(number));
E N D
陣列與多型 借用上一章中,Worker、HourlyWorker 以及 SalaryWorker的範例來說明多型應用於陣列的情形。 公司內有些員工是 SalaryWorker,有些是 HourlyWorker。 Worker[] w = new Worker[5]; if(choice.equals("h")) { number = JOptionPane.showInputDialog("輸入工作時數"); w[i] = new HourlyWorker(name, Integer.parseInt(number)); } else { number = JOptionPane.showInputDialog("輸入年薪"); w[i] = new SalaryWorker(name, Integer.parseInt(number)); }
練習題 • 請修改上述人事系統,使得該系統也能分別產生 HourlyWorker 和 SalaryWorker 的總薪資。 • (Optional)為了提高重複使用性,請設計一個 Personnel 類別,該類別物件包含全公司的員工薪資資料,除了計算總薪資之外,使用者還可以經由 add()、delete()、update()、query() 來新增、刪除、修改、查詢員工薪資。
練習題 • 繼續之前 Circle/Rectangle 的範例, • 請設計一套系統,使得使用者可以產生[任意/固定]個 Circle 或者 Rectangle 物件,也允許使用者在任意時間指定某特定物件的周邊長/面積,或者目前各種物件的個數、總周邊長、總面積等資訊。 • 顯示物件資訊的格式: • Circle 總數為 2 • 半徑為 4.2 • 半徑為 3.1 • Rectangle 總數 1 • 長為 1.2、寬為 4.5
陣列與 main 方法 在控制類別內的 main 方法 public static void main(String[] args) { javac Test.java dir /w *.java args.length為4 java Test 1 22 3 14
範例 • java Test1 this is a book • java Test1 “this is” “a book” • args.length 為 2,args[0] 為 this is,而 args[1]為 a book
練習題 • 請完成 Test1。 • 請寫一個控制類別,使得如果使用者輸入java TestWorker h John 44,則程式會產生一個 HourlyWorker 的物件,並列印出John 的薪資;同樣的,如果使用者輸入java TestWorker s Mary 420000,則程式會產生一個 SalaryWorker 的物件,並列印出 Mary 的薪資。
練習題 • JOptionPane.showOptionDialog( ) 允許你做出一個可供選擇的對話視窗,而允許使用者選取的字串放在一個陣列中。請參考 JOptionPane.showOptionDialog( ) 的文件,並修改之前的 TestWorker,使得使用者只用選擇 HourlyWorker 或者 SalaryWorker。
練習題 • 假設公司內有三個部門,分別是人事室、行銷課、以及製造課。每一個課裡面都只有 5 個員工,每一個員工不是 HourlyWorker、就是 SalaryWorker。請利用隨機的方式決定員工是 HourlyWorker、還是 SalaryWorker,也利用隨機的方式產生薪資或者工作時數,至於員工姓名就以代號從 1 編到 15。最後,請計算並列印出每一個員工的清單、該部門的總薪資、以及該公司的總薪資。 • (Optional) 請設計一個 Personnel 的類別來代表前一題中的陣列。
陣列的限制 • 陣列很好用,可是一旦它的大小確定了之後,它的大小就不能改變。 • Worker[] w = new Worker[5]; • 當 w 不足以存放公司的員工時,我們必須 • Worker nw = new Worker[10]; • 將 w 的內容一個個複製到 nw。 • 可以 w = nw; 嗎? • 陣列可以輕易的新增、刪除、修改、查詢嗎?
ArrayList • ArrayList 和 TreeMap 是 Java 提供的類別,它們的目的跟陣列相同,都是為了能夠有效處理一堆物件的一種資料結構 • 這兩個類別都是屬於 java.util 這個套件內 • 這些用來處理一堆物件的類別統稱為 JCF (Java Collection Framework)
ArrayList 特色 • 因為一個 ArrayList 沒有所謂的大小限制,程式設計師也不必事先決定一個 ArrayList 的大小 • 我們可以隨時加進一個物件,而不必擔心加入一個物件之後會不會超出陣列原先設定的大小,想加就加 • 想要把 ArrayList 中的元素移除,直接使用remove() 的方法直接移除 • 想要取得 ArrayList 中的某個特定位置的物件,也可以像陣列一樣,指定索引值就可以
ArrayList • List 的觀念其實很像陣列,以數學的表達方式就像 • L=(l0, l1, l2,…, lN) • L 代表一個 List,而每一個 List 裡面包含許多元素 • 以我們常見的座標(x, y)和(x, y, z)為例,l0 就是 x,l1 就是 y,而 l2 就是 z
常用的方法 • boolean add(E e):這個方法會把傳進來的物件 e 加到 list 的最後面; • 如果加入的動作完成,則回傳 true。至於 e 的資料型態為 E,這代表泛型,我們暫時把它當成一個類別型態 • void add(int index, E e):如果需要把傳進來的物件 e 加到 list 的某個特定位置 index,則使用這個 add() 方法 • void clear():這個方法會把 list 內的所有元素刪除 • E get(int index):這個方法會取得 list 內位於 index 位置的物件 • E remove(int index):這個方法會把 list 內的位於 index 的元素刪除,並將刪除的元素回傳 • E set(int index, E e):這個方法會把傳入的 e 用來取代原先在 index 位置的舊元素,並且把舊元素回傳 • int size():回傳 list 目前所擁有的元素數量
程式改寫 • 第30-31行,其實這兩行可以改成 • System.out.println( ( (Worker) p.get(i) ).toString()); • TestList.java uses unchecked or unsafe operations. • 必須使用泛型來消除
練習題 • 請把 TestList 的第 17-19 行,改寫成一行,而不需要另外宣告一個 Worker 物件w。
泛型(Generic Type) • 讓我們以 add() 和 get() 這兩個方法來說明。在 JDK 1.5 版之前,這兩個方法的定義如下: • void add(Object o):這個方法是用來將物件 o加入 ArrayList • Object get(int index):這個方法是取得位於index 的物件,該物件的資料型態為 Object • 由於 Object 是所有類別的祖先類別,且由於繼承的特色(或者嚴格的說,向上轉型的特色),我們可以在 ArrayList 中加入任意物件,例如我們可以加入Worker、HourlyWorker、Product、Book、String、Date 等
執行結果 將程式的第 30 行 Worker w = (Worker) p.get(i);改成 Worker w = p.get(i);
泛型 • 畫面中顯示: • p.get(i) 回傳的是 Object,當然無法 downcast,一定需要強迫轉型。 • 所謂的 ”unsafe operation” 跟 type safety有關:所謂 type safety 的問題,說的是如果一個程式語言的設計可以避免發生資料型態轉換的錯誤,那麼這個程式語言就是 type safe。
範例 ArrayList any = new ArrayList(); any.add(“Hello”); any.add(new Worker(“John”, 34000)); any.add(new Date()); any 是一個 ArrayList 的物件,其第一個位置的物件是一個字串,第二個位置的物件是一個 Worker 物件,而第三個位置的物件是一個 Date 物件
範例 如果位置忘了,而不小心寫成 Worker w = (Worker) any.get(2); 編譯沒問題,在執行時卻出了狀況,這代表一個 unsafe 的狀況。好的設計,應該在編譯的時候就指出問題。
泛型宣告 • 泛型宣告的方式就是在 ArrayList(或者其他 JCF 的類別)之後加上一對 <、> 括號 • 在 <> 之中加入所需要的類別 • 假設我們希望產生的 any 是一個 ArrayList 物件,而且其元素都屬於 String 型態,那麼我們就可以把 any 宣告成 • ArrayList<String> any = new ArrayList<String>();
範例 import java.util.*; public class TestList3 { public static void main(String[] args) { ArrayList<String> any = new ArrayList<String>(); any.add("Hello"); any.add(new Worker("John", 34000)); any.add(new Date()); Worker w = (Worker) any.get(2); } }
泛型 • 由於 Java 支援泛型,Java 是一個 type safe 的程式語言。 • 這個特色是在 JDK 1.5 版之後才有的
練習題 • 在之前的範例中,我們宣告了 Circle/Rectangle 的陣列,這次請改成利用 ArrayList 來代表並使用泛型,請做必要的修改。
TreeMap • Map 的資料結構基本上是像是一個有兩個欄位的表格 • 第一個欄位叫做 key,第二個欄位代表資料 • 在 Map 中的每一筆資料都是由(key, 資料)所表示 • 這樣成雙成對的結構叫做 entry,或叫作 map entry
TreeMap • 在 ArrayList 裡面找資料,程式需要從第一筆一直找到最後一筆,或者一直找到為止 • 而 Map 的作用就在於,只要程式設計人員指定一個資料的 key 值(可以把它想成資料的名稱),Map 就會把對應於該 key 值的資料傳回來
常用的幾個方法 • V put(K key, V value):把傳進來的物件 value 加到 map的 key 的位置上; • 如果之前在 key 所在的位置上沒有資料,put() 回傳 null;反之,如果之前在 key 所在的位置上已經有資料了,則 value 會取代原來的資料,而且 put() 回傳原來的資料 • void clear():將 map 內的所有 entry 刪除。 • V get(Object key):取得 map 內對應於 key 值的資料 • V remove(Object key):依據 key 找出 map 內的 entry 予以刪除,並將刪除的資料回傳。 • 如果 remove() 找不到對應的 key,則回傳 null • int size():回傳 map 內目前所擁有的 entry 數量
TreeMap • TreeMap 實作 Map,因此 TreeMap 也提供了這幾個方法給程式設計人員使用 • 在下列的範例中,我們利用 TreeMap 的資料結構來取代之前的 Worker 陣列personnel
06 TreeMap<String,Worker> personnel = new TreeMap<String,Worker>(); 11 personnel.put("M001", new Worker("John", 32000)); 12 personnel.put("A003", new Worker("Mary", 34000)); 13 personnel.put("M010", new Worker("Dave", 25000)); 16 Worker w = (Worker) personnel.get("A003"); 17 w.setName("Eric"); 18 personnel.put("A003", w); 19 personnel.remove("M001"); 22 w = (Worker) personnel.get("M001"); 23 if(w != null) 24 System.out.println(w.toString()); 26 w = (Worker) personnel.get("A003"); 27 if(w != null) 28 System.out.println(w.toString()); 30 w = (Worker) personnel.get("M010"); 31 if(w != null) 32 System.out.println(w.toString());
練習題 • 請修改 TestMap 的第 22-32 行,使得修改後,只有下列三行,並新增所需要的display()方法: display(“M001”, personnel); display(“A003”, personnel); display(“M010”, personnel); • 請問,如果事先並不知道一個 TreeMap 中的 (key, value) pairs 有哪些,請問有什麼辦法可以把所有的 (key, value) pairs 列印出來?(提示:查看 APIs)
傳遞”任意個”引數給方法 • 傳統上,當定義方法的時候,我們已經決定了該方法的參數個數;可是,有時候我們去需要定義一個方法,使得呼叫端方法可以傳遞”任意個”引數給該方法! • 例如:我們常用的 String.format(String format, Object… args)。仔細想想,我們可以在 “format” 之後,加上任意個參數。
傳遞”任意個”引數給方法 • Java 支援這種定義方式,而這樣的結構稱為 “varargs”。 • 使用 varargs 來定義方法,其方式是在參數資料型態的後面立即(不能有空格)加上三個點 • public void display(String… msg) • msg 的處理方式跟陣列相同 • 呼叫端可以傳遞任意個引數(也可以沒有) • display() • display(“Hello”); • display(“Hello”, “World”); • display(字串陣列); • 資料型態可以是基本資料型態,也可以是類別。
範例 private static void display(String... msg) { System.out.println(msg.length); for(int i=0; i<msg.length; i++) System.out.println(msg[i]); System.out.println(); } private static void display(int... num) { System.out.println(num.length); for(int i=0; i<num.length; i++) System.out.println(num[i]); System.out.println(); } } public class TestMM { public static void main(String[] args) { display("Hello"); display("Hello", "World"); display("Hello", "World", "Again"); display(1); display(1,2); display(1,2,3); }