---
# System prepended metadata

title: Java - Generics的一些細節
tags: [Java, Basic Java]

---

# Java - Generics的一些細節
###### tags: `Java` `Basic Java`

## 1. 通用符號：?

假設現在要設計一款汽車比賽，並且包含Benz跟BMW這兩個品牌的汽車

依照正常設計邏輯，我們需要設計一個Car的類別、再分別設計Benz與BMW兩個子類去繼承Car

```
class Car{

}

class Benz extends Car {

}

class BMW extends Car {

}
```

然後為了存取資料方便，我們使用ArrayList進行數據存取
並設計一個共用方法讓兩個類別都可以使用
結果發現出現編譯錯誤了

```
public class Demo {
    public static void main(String[] args) {
        ArrayList<Benz> benz = new ArrayList<>();
        benz.add(new Benz());
        benz.add(new Benz());
        benz.add(new Benz());

        go(benz); -> Compiling Error!!!

        ArrayList<BMW> bmws = new ArrayList<>();
        bmws.add(new BMW());
        bmws.add(new BMW());
        bmws.add(new BMW());

        go(bmws); -> Compiling Error!!!

    }

    public static void go(ArrayList<Car> Cars) {

    }

}
```

出現編譯錯誤的原因：
**Java認為 ArrayList<Benz>/ArrayList<BMW> 跟ArrayList6<Car>是兩個不一樣的東西，所以沒辦法當成參數進行傳入**
    
此時解法就是使用**?**這個通用符號來當作類型
```
    public static void go(ArrayList<?> Cars) {

    }
```

但假設今天原本的需求中新增了一個Dog類別，用同樣的ArrayList裝進Dog object之後，卻發現Dog也可以使用這個共用方法了。
雖然編譯沒有出現錯誤，但是整個設計邏輯卻出現了錯誤
```
class Dog{
    
}

---

        ArrayList<Dog> dogs = new ArrayList<>();
        dogs.add(new Dog());
        dogs.add(new Dog());
        dogs.add(new Dog());

        go(dogs); -> No comiling error but STRANGE!!
```


針對這個問題，我們就要使用Bounded Type Parameters來解決

**? extends 父類別** 代表參數只能傳入繼承該父類別的子類別

```
    public static void go(ArrayList<? extends Car> Cars) {

    }
```

此時 go(dogs);這一行程式就會出現錯誤

另外有個? super 子類別的用法，但比較少用