# 泛型(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精準比對

* **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`