---
# System prepended metadata

title: 泛型(Generic Type)
tags: [Java2, Java]

---

# 泛型(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`