# 泛型(Generic Type) <style> hr.new1 { border-top: 1px solid black; } hr.new2 { border: 0; height: 1px; width : 80%; background-image: linear-gradient(to right, rgba(0,0,0,0), rgba(0,0,0,0.75), rgba(0,0,0,0)); } div.hr4{ border:2px #C0C0C0 dashed; width:600px } u.r{ text-decoration-color:red } b.r{ color:red; } </style> #### 在有泛型前的做法 ```java= public class BeforeGenericList {//泛型之前 public static void main(String[] args) { List data = new ArrayList(); data.add("Hello"); data.add("World"); data.add(123); Iterator it = data.iterator(); while (it.hasNext()) { // String str = (String) it.next(); // 強制轉型 // System.out.println(str); //以下為泛型 之前 避免轉型錯誤的方法 Object obj = it.next(); //避免集合的轉型錯誤if else蓋好蓋滿,所以泛型 if(obj instanceof String) { String str = (String)obj; System.out.println(str); }else if(obj instanceof Integer) { Integer i1 = (Integer)obj; System.out.println(i1.intValue()); } } } } ``` #### 泛型 ```java= public class GenericList { public static void main(String[] args) { List<String> data = new ArrayList<String>(); //< >內只能放類別Object,例:int需要用Integer //< >裡只能放一個類別 //除非是Map<key,value> //改< >裡的型別,add()方法型態動態改變 data.add("Hello"); data.add("World"); // data.add(123);//泛型,執行前就會錯誤 Iterator<String> it = data.iterator(); while (it.hasNext()) { String str = it.next(); // 強制轉型,不再需要 System.out.println(str); } } } ``` * 較複雜的泛型,除了在List部分,Set和Map系列當然也支援泛型 ```java= public class GenericMap { public static void main(String[] args) { Map<Integer, String> map = new HashMap<Integer, String>(); //<key,value> for (int i = 0; i < 3; i++) { map.put(new Integer(i), "number" + i); //依序放入key,value } System.out.println(map.get(0));//自動拆裝相 System.out.println(map.get(new Integer(1))); System.out.println(map.get(new Integer(2))); } } ``` ```java= class MyGenericType<Type> { //Type為隨意取名,可以改,隨使用者自訂泛型改變 //給之後的使用者決定 private List<Type> list; public MyGenericType() { list = new Vector<Type>(); } public void add(Type t) { list.add(t); } public Type get(int i) { return list.get(i); } } /* 以上為設計者 */ /* 以下為使用者 */ public class MyGeneric { public static void main(String[] args) { MyGenericType<String> myGeneric = new MyGenericType<String>(); //這裡< >宣告型別,上方的Type會動態改變 for (int i = 0; i < 3; i++) { myGeneric.add("number"+ i); System.out.println(myGeneric.get(i)); } } } ``` ### 泛型的進階設定 - 泛型的設定可使用「?」搭配「extends」或「super」來增加泛型的彈性 - 如: - `<? extends Number>`:代表可以是Number或Number的子類別 - `<? super Number>`:代表可以是Number的父類別 ```java class Book<T>{ T price;//型別由操作的使用者決定Integer等繼承Number的型別 //(Book<Integer> book) public static void show(Book<? extends Number> b){//是Number或其子類都可以使用 //以防有人犯賤把main的泛型刪掉 System.out.println("書籍定價為:" + b.price); } } //此例為跨區域有可能使用Double public class GenericAdv { public static void main(String[] args){ Book<Integer> book = new Book<Integer>(); book.price = 580; Book.show(book);//顯示此書物件的價格 } } ``` ## Iterable介面 * 從JDK1.5開始,Collection介面增加了新的泛型(Generic Type)功能 設計,並繼承JDK1.5的新介面Iterable * 介面Iterable(JDK1.5): - 此介面只有一個iterator()方法,回傳iterable介面 - `Iterable<T>` iterator() * 實作Iterable介面,其目的是為了允許物件可以使用JDK1.5的「增強 型for迴圈(for-each)」語法 - Implementing this interface allows an object to be the target of the “foreach” statement 註:當使用JDK1.5的for-each來走訪集合的元素內容時,一切將顯得格外輕鬆! ### 增強型for迴圈 (for – each) * 增強型的for迴圈 (Enhanced for Loop) – for each: - 在JDK1.5中,針對for迴圈作了一些加強,讓我們無需知道陣列 (array) 或集合(collection)的長度,甚至也不用迭代器(iterator),便 可以將其中的元素一一取出 - 使用for – each來走訪集合的元素會格外輕鬆 * 語法: - **for (<資料型態> <變數宣告> : <陣列或集合>) - for (Type varName : listName)** * 即可將listName裡的元素依順序,由型別為Type的變數 varName存取 * **陣列或集合中元素的型別必須是可以轉型為Type的型別** ```java= public class EnhanceForAttention { public static void main(String[] args) { List<String> data = new ArrayList<String>(); data.add("David1"); data.add("David2"); data.add("David3"); for (int i = data.size() - 1; i >= 0; i--) System.out.println(i + ": " + data.get(i)); System.out.println(); for (String str : data) // ※倒著取,以上我做不到 System.out.println(str); // ※傳統for迴圈, 薑老的辣 } } ``` ```java= public class EnhanceForMap { public static void main(String[] args) { Map<Integer, String> map = new HashMap<Integer, String>(); for (int i = 0; i < 6; i++) { map.put(i, "David" + i); } for (String val : map.values()) { System.out.println(val); } } } ``` ## 集合比較! #### 基礎依大小排序(數字、字串) * 比較數字、字串無須實作comparable介面 ```java= public class TestArraysForArray { public static void main(String args[]) { String strArray[] = { "5", "20", "3", "4", "1" }; Arrays.sort(strArray);//排序字串,按照開頭字大小 //Arrays.sort()只能排列陣列,無法排列類別 for (int i = 0; i < strArray.length; i++) { System.out.println(strArray[i]); } } } ``` > [color=#3437e5]列出 1 20 3 4 5 ```java= public class TestCollectionsForList { public static void main(String args[]) { List list = new ArrayList(); list.add("5"); list.add("20"); list.add("3"); list.add("4"); list.add("1"); Collections.sort(list);//按照字串低一個字大小排序 //Collections.sort(),只能排列集合 // Collections.reverse(list); Object obj; for (int i = 0; i < list.size(); i++) { obj = list.get(i); System.out.println(obj); } } } ``` > [color=#ef9043]列出 1 20 3 4 5 #### 物件的大小排序 * **類別陣列** ```java= public class TestArraysForArrayEmp { public static void main(String args[]) { Employee e[] = new Employee[5]; Employee e1 = new Employee(7001, "king1"); Employee e2 = new Employee(7002, "king2"); Employee e3 = new Employee(7003, "king3"); Employee e4 = new Employee(7004, "king4"); Employee e5 = new Employee(7005, "king5"); Employee e6 = new Employee(7005, "king5"); e[0] = e5; e[1] = e2; e[2] = e3; e[3] = e4; e[4] = e1; System.out.println(e[4].getEmpno()); Arrays.sort(e); //實作了comparable介面,按照Empno排列,改變陣列內的排序 //沒有實作無法比較錯誤,會出現ClassCastException System.out.println(e[4].getEmpno()); System.out.println("========="); for (int i = 0; i < e.length; i++) { System.out.println(e[i].getEmpno() + "-" + e[i].getEname()); } } } ``` > [color=#e88e68]列出 7001 7005 ========= 7001-king1 7002-king2 7003-king3 7004-king4 7005-king5 * **ArrayList** ```java= public class TestCollectionsForListEmp { public static void main(String args[]) { List<Employee> list = new ArrayList<Employee>(); Employee e1 = new Employee(7001, "king1"); Employee e2 = new Employee(7002, "king2"); Employee e3 = new Employee(7003, "king3"); Employee e4 = new Employee(7004, "king4"); Employee e5 = new Employee(7005, "king5"); Employee e6 = new Employee(7005, "king5"); list.add(e5); list.add(e2); list.add(e3); list.add(e4); list.add(e1); list.add(e6);//ArrayList,重複一樣加入 Collections.sort(list); //實作了Comparable介面,可以比較類別指定屬性 //沒有使用sort(),會按照加入物件順序列出 // Collections.reverse(list); for (Employee aEmp : list) { System.out.println(aEmp.getEmpno() + "-" + aEmp.getEname()); } } } ``` > [color=#ef9043]列出 7001-king1 7002-king2 7003-king3 7004-king4 7005-king5 7005-king5 * **TreeSet** ```java= Set<Employee> set = new TreeSet<Employee>(); Employee e1 = new Employee(7001, "king1"); Employee e2 = new Employee(7002, "king2"); Employee e3 = new Employee(7003, "king3"); Employee e4 = new Employee(7004, "king4"); Employee e5 = new Employee(7005, "king5"); Employee e6 = new Employee(7005, "king5"); set.add(e5); set.add(e2); set.add(e3); set.add(e4); set.add(e1); set.add(e6); //比較類別必須實作Comparable介面,才能實現有類別物件序性, //否則add()時就會出現ClassCastException //否則只有基本型別有序 //有序性,也有Set重複不加入的特性 for (Employee aEmp : set) { System.out.println(aEmp.getEmpno() + "-" + aEmp.getEname()); } ``` > [color=#e2385d]列出 7001-king1 7002-king2 7003-king3 7004-king4 7005-king5 * **HashSet** ```java= Set<Employee> set2 = new HashSet<Employee>(); Employee em1 = new Employee(7001, "king1"); Employee em2 = new Employee(7002, "king2"); Employee em3 = new Employee(7003, "king3"); Employee em4 = new Employee(7004, "king4"); Employee em5 = new Employee(7005, "king5"); Employee em6 = new Employee(7005, "king5"); set2.add(em5); set2.add(em2); set2.add(em3); set2.add(em4); set2.add(em1); set2.add(em6); //如沒有實作hashCode()、equals(),會無法比較物件內的參數的不同 //會出現e5、e6都出現的狀況 for (Employee aEmp2 : set2) { System.out.println(aEmp2.getEmpno() + "-" + aEmp2.getEname()); } ``` > [color=#ef9043]列出 7005-king5 7002-king2 7003-king3 7004-king4 7001-king1 * **TreeMap&HashMap** ```java= // Map<Employee , String> map = new HashMap<Employee , String>(); //必須實作hashCode()、equals(),才有不重複特性 Map<Employee, String> map = new TreeMap<Employee, String>(); // <Employee, String>TreeMap的Key值要同一種資料型別 //必然的必須實作Comparable介面,有序性,不會重複 Employee e1 = new Employee(7001, "king1"); Employee e2 = new Employee(7002, "king2"); Employee e3 = new Employee(7003, "king3"); Employee e4 = new Employee(7004, "king4"); Employee e5 = new Employee(7005, "king5"); Employee e6 = new Employee(7005, "king5"); map.put(e5, e5.getEname());//<Employee, String> map.put(e2, e2.getEname()); map.put(e3, e3.getEname()); map.put(e4, e4.getEname()); map.put(e1, e1.getEname()); map.put(e6, e6.getEname()); System.out.println(map.values());//列出Collection型態的集合view System.out.println(map.keySet());//列出ex的Set型態位址 for (String ename : map.values()) { System.out.println(ename); } System.out.println(); for (Employee aEmployee : map.keySet()) { System.out.println(aEmployee.getEmpno()); } ``` > [color=#ef9043]TreeMap列出 [king1, king2, king3, king4, king5] [ch03.Employee@6188b02, ch03.Employee@6188b22, ch03.Employee@6188b42, ch03.Employee@6188b62, ch03.Employee@6188b82] king1 king2 king3 king4 king5 _ 7001 7002 7003 7004 7005 HashMap列出 king5 king2 king3 king4 king1 _ 7005 7002 7003 7004 7001 * **`Collectios.sort(List<T> list);`** * **`Arrays.sort(Object o);`** * 所有在List的元素必須實作Comparable介面 * 必須是相同資料類型,不然會拋出ClassCastException :::info * 最大差異為一個是排序物件陣列,一個為排列Collection ::: HashBuket雜湊桶 先比對hashCode(),重複再equals精準比對 ![](https://i.imgur.com/VPuCbnK.png) * **TreeSet** * <b class="r">自訂類別物件</b>使用TreeSet做排序與==不重複==,操作<font size="20">必然</font><b class="r">需實做Comparable介面compareTo方法</b>要有相等的結果設計(一樣大回傳0) * **如放類別物件不比較也需要實作Comparable介面,因為TreeSet會自己排序** * 如果只有數字不需要實作Comparable介面 * **HashSet** * <b class="r">自訂類別物件</b>使用HashSet做不重複須<b class="r"><font size="15">主動</font>改寫Object類別的hashCode與equals方法,否則會重複!</b> * **ArrayList** * 連續線性排列 * 好處-搭配索引值存取快 * 壞處-不適合常進行元素插入或移除 * 移除元素後其他元素需往前遞補 * **LinkedList** * 好處,壞處與ArrayList相反 * 元素新增移除只需要改變節點資料 HashSet無序 TreeSet有序性 LinkedHashSet依加入順序 :::info #### 進階排序集合 * 依加入順序 : LinkedList、LinkedHashSet、LinkedHashMap * 依大小順序 : Queue、PriorityQueue、 * 依加入順序(FIFO、LIFO) : (FIFO)Vector、(LIFO)Stack ::: ###### tags: `Java2`,`Java`