# 泛型相關

Java 泛型是一种支持参数化类型的机制，它可以让代码更加通用和安全。通过使用泛型，我们可以在编写代码时使用占位符类型（如 T、E 等），然后在实际使用时再指定具体类型。这样就可以使代码更加灵活，可以避免类型转换错误和运行时异常。

Java 泛型的基本用法是使用尖括号 "&lt;&gt;" 括起来的一个或多个类型参数，这些类型参数可以用于类、接口、方法的声明中。例如：

```Java
public class MyClass<T> {
    private T data;

    public MyClass(T data) {
        this.data = data;
    }

    public T getData() {
        return data;
    }
}

```

在上面的代码中，我们使用了一个类型参数 T，这个参数可以用于 MyClass 类中的任何地方，包括类的字段、方法参数、方法返回值等等。

而&lt;?&gt;和&lt;T&gt;的区别在于，&lt;?&gt;是一种无限制通配符类型，表示可以匹配任何类型，而&lt;T&gt;则是一个类型参数，表示在使用时需要指定具体的类型。例如：

```Java
List<?> list = new ArrayList<>();
List<String> strList = new ArrayList<>();
list = strList; // 合法，因为 list 可以匹配任何类型

```

```Java
public <T> T getValue(T[] array, int index) {
    return array[index];
}

String[] strArray = {"hello", "world"};
String str = getValue(strArray, 0); // 合法，因为在使用 getValue 时指定了类型参数为 String

```

---

下面是一个使用无限制通配符类型（&lt;?&gt;）的例子，我们定义了一个方法，可以接受任何类型的 List，并打印出其中的元素：

```Java
public static void printList(List<?> list) {
    for (Object element : list) {
        System.out.println(element);
    }
}

```

这个方法的参数列表中使用了无限制通配符类型（&lt;?&gt;），表示可以匹配任何类型的 List。在方法内部，我们使用了一个 for-each 循环遍历 list，并打印出其中的元素。

使用这个方法时，我们可以传入任何类型的 List，例如：

```Java
List<Integer> intList = Arrays.asList(1, 2, 3);
List<String> strList = Arrays.asList("hello", "world");
List<Object> objList = Arrays.asList(1, "hello", true);

printList(intList); // 输出 1, 2, 3
printList(strList); // 输出 hello, world
printList(objList); // 输出 1, hello, true

```

如果我们将上面的例子中的方法参数从无限制通配符类型（&lt;?&gt;）改为类型参数（&lt;T&gt;），那么代码将变成下面这样：

```Java
public static <T> void printList(List<T> list) {
    for (T element : list) {
        System.out.println(element);
    }
}

```

这个方法的参数列表中使用了类型参数（&lt;T&gt;），表示在使用时需要指定 List 中元素的具体类型。在方法内部，我们使用了一个 for-each 循环遍历 list，并打印出其中的元素。

使用这个方法时，我们需要指定 List 中元素的具体类型，例如：

```Java
List<Integer> intList = Arrays.asList(1, 2, 3);
List<String> strList = Arrays.asList("hello", "world");
List<Object> objList = Arrays.asList(1, "hello", true);

printList(intList); // 输出 1, 2, 3
printList(strList); // 输出 hello, world
printList(objList); // 编译错误，因为 objList 中的元素类型不是 Object

```

在使用时，我们需要指定 List 中元素的具体类型，例如使用 `printList(Integer)` 或 `printList(String)`，这样才能保证参数类型的匹配，否则将会编译错误。

---

在 Java 泛型中，类型参数的名称是可以任意指定的，通常使用以下的约定：

- T：表示任何类型。
- E：表示集合中的元素类型。
- K：表示映射中的键类型。
- V：表示映射中的值类型。
- N：表示数字类型。
- S、U、V 等：表示其他任意类型。

因此，使用 &lt;T&gt; 或 &lt;E&gt; 在语义上是等价的，只是名称不同而已。

除了以上提到的常用类型参数名称外，开发者也可以根据实际情况自行定义类型参数的名称，只需要遵循命名规范即可。不过，为了代码可读性和可维护性，建议使用常见的类型参数名称。

需要注意的是，不同的类型参数名称并没有实质上的差异，只是在语义上有所不同，因此选择类型参数名称时应根据实际情况和需求进行选择，选择一个能更好地表达自己的代码意图的名称。

---

 一個回傳任意型別的範例

```Java
public static <T> T anyTypeMethod(T arg) {
    if (arg == null) {
        // 返回空对象
        return (T) new Object();
    }
    // 方法逻辑
    return arg;
}
```

在这个方法中，我们首先检查参数是否为 `null`。如果参数为 `null`，则返回一个空对象，否则执行方法的逻辑，将参数原封不动地返回。

需要注意的是，在这个方法中，我们创建了一个新的 `Object` 对象并将其转换为泛型类型，这是为了避免空对象时返回类型不匹配的问题。因为 Java 中的泛型是在编译时进行类型擦除的，如果我们直接返回一个 `null`，编译器将无法确定返回值的类型，可能会导致编译错误或运行时异常。

使用这个方法时，我们可以传入任何类型的参数，并获取返回值，如果传入参数为 `null`，则返回一个空对象，例如：

```Java
Integer intValue = anyTypeMethod(123);
String strValue = anyTypeMethod("hello");
Object objValue = anyTypeMethod(new Object());
Object nullValue = anyTypeMethod(null);

System.out.println(intValue); // 输出 123
System.out.println(strValue); // 输出 "hello"
System.out.println(objValue); // 输出 Object 对象的 toString() 值
System.out.println(nullValue); // 输出 "java.lang.Object@hashcode"

```

在这个示例中，我们分别传入了一个整数、一个字符串、一个对象和一个 `null`，然后获取了相应的返回值。当传入参数为 `null` 时，返回一个空对象，其类型为 `Object`。