Generic method: public <T> void myMethod(T data) { ... }
Naming conventions for generics:
T: Type parameter
E: Element or Entry type
K, V: Key and Value types
Finally, again let’s take note of the naming convention used for the type parameters. We use T for type, whenever there isn’t anything more specific about the type to distinguish it. This is often the case in generic methods. If there are multiple type parameters, we might use letters that neighbor T in the alphabet, such as S. If a generic method appears inside a generic class, it’s a good idea to avoid using the same names for the type parameters of the method and class, to avoid confusion. The same applies to nested generic classes. Oracle Java Tutorials
Use Generic In Java
在 Java 中使用泛型可以提高代码的类型安全性和可重用性,但也有一些需要注意的地方和使用限制。
Best Practices
Method Overload
重载方法在泛型类型经过类型擦除后可能会产生冲突,应避免在同一类中定义仅泛型类型参数不同的方法重载
1 2 3 4 5
// 编译器报错:Erasure of method method(List<String>) is the same as another method in type Mainpublic class Main { public void method(List<String> list) { ... } public void method(List<Integer> list) { ... }}
// 1. ConstructorMap<String, List<String>> myMap = new HashMap<String, List<String>>();// You can substitute the parameterized type of the constructor with an empty set of type parameters (<>):Map<String, List<String>> myMap = new HashMap<>();// 2. Method invocation// 代码引用自@pdai: https://pdai.tech/md/java/basic/java-basic-x-generic.htmlpublic class Test { public static void main(String[] args) { /** 不指定泛型的时候 */ int i = Test.add(1, 2); // 这两个参数都是Integer,所以T为Integer类型 Number f = Test.add(1, 1.2); // 这两个参数一个是Integer,一个是Float,所以取同一父类的最小级,为Number Object o = Test.add(1, "asd"); // 这两个参数一个是Integer,一个是String,所以取同一父类的最小级,为Object /** 指定泛型的时候 */ int a = Test.<Integer>add(1, 2); // 指定了Integer,所以只能为Integer类型或者其子类 int b = Test.<Integer>add(1, 2.2); // 编译错误,指定了Integer,不能为Float Number c = Test.<Number>add(1, 2.2); // 指定为Number,所以可以为Integer和Float } // 这是一个简单的泛型方法 public static <T> T add(T x, T y) { return y; }}
Avoid using Raw Types
在下面的代码中,使用了 Raw type List,这在现代 Java 中是不推荐的。Raw type 是为了向后兼容 Java 5 之前的代码而存在的,但它们绕过了泛型类型检查,可能会导致运行时的 ClassCastException
1 2 3 4 5 6
// Warning: List is a raw type. References to generic type List<E> should be parameterizedList list = new ArrayList();list.add("Hello");// Recommended: Use generic type List<String>List<String> list = new ArrayList<>();
Restrictions on Generics
Cannot Instantiate Generic Types with Primitive Types
Cannot Create Instances of Type Parameters
Cannot Declare Static Fields Whose Types are Type Parameters
Cannot Use Casts or instanceof With Parameterized Types
Cannot Create Arrays of Parameterized Types
Cannot Create, Catch, or Throw Objects of Parameterized Types
Cannot Overload a Method Where the Formal Parameter Types of Each Overload Erase to the Same Raw Type
class Pair<K, V> { private K key; private V value; public Pair(K key, V value) { this.key = key; this.value = value; } public K getKey() { return key; } public V getValue() { return value; }}public class Main { public static void main(String[] args) { Pair<String, Integer> pair = new Pair<>("key", 123); System.out.println(pair.getKey()); // Output: key System.out.println(pair.getValue()); // Output: 123 }}
A class’s static field is a class-level variable shared by all non-static objects of the class. Hence, static fields of type parameters are not allowed. Consider the following class:
1 2 3 4 5 6 7 8
public class MobileDevice<T> { private static T os; // ...}// If static fields of type parameters were allowed, then the following code would be confused:MobileDevice<Smartphone> phone = new MobileDevice<>();MobileDevice<Pager> pager = new MobileDevice<>();MobileDevice<TabletPC> pc = new MobileDevice<>();
Because the static field os is shared by phone, pager, and pc, what is the actual type of os? It cannot be Smartphone, Pager, and TabletPC at the same time. You cannot, therefore, create static fields of type parameters.
public class Pair<T> { private T key; private T value; public Pair(T key, T last) { this.key = value; this.value = valuet; } public T getFirst() { ... } public T getLast() { ... } // a. 使用泛型方法 // 将泛型类型参数定义在方法级别,而不是类级别。 public static <K> Pair<K> create(K first, K last) { return new Pair<K>(first, last); } // b. 使用通配符或具体类型 // 在静态方法中使用通配符或具体类型参数,而不是类的泛型类型参数 public static void staticMethod(List<?> list) {...} // 使用具体类型 public static void staticMethod(List<String> list) {...}}
public class Collections { public static <T extends Comparable<? super T>> void sort(List<T> list) { list.sort(null); } public static <T> void sort(List<T> list, Comparator<? super T> c) { list.sort(c); }}
public class Arrays { @SafeVarargs public static <T> List<T> asList(T... a) { return new ArrayList<>(a); }}// usage examplepublic class Main { public static void main(String[] args) { List<String> list = Arrays.asList("Banana", "Apple", "Cherry"); Collections.sort(list); System.out.println(list); // 输出: [Apple, Banana, Cherry] }}