-
为什么需要泛型: 泛型是Java语言中的一项重要特性,它的出现主要是为了提高代码的灵活性、安全性和重用性。在没有泛型之前,集合类(如List、Set、Map等)只能存储Object类型的对象,使用时需要进行强制类型转换,容易引发类型转换异常。而引入泛型后,可以在编译阶段对数据类型进行检查,减少了运行时出现的类型错误,提升了代码的可读性和可维护性。
-
什么是泛型: 泛型是一种参数化类型的机制,允许在定义类、接口或方法时使用类型参数,参数化类型在实际使用时会被具体的数据类型替代,使代码更具通用性和可复用性。泛型可以应用于类、接口、方法和数组等多种场景。
-
自定义泛型接口、泛型类: 可以通过在接口或类名后面添加尖括号(<>)来定义泛型。例如,可以声明一个泛型接口:
public interface MyInterface<T> { void doSomething(T item); }
或者一个泛型类:
public class MyClass<T> { private T value; public T getValue() { return value; } public void setValue(T value) { this.value = value; } }
在使用时,可以通过具体的数据类型来实例化泛型接口或泛型类。
-
通配符: 通配符(Wildcard)是一种特殊的泛型类型,用来表示未知类型。通配符分为上界通配符(? extends T)和下界通配符(? super T)。其中,上界通配符用于指定上界限制,表示参数化类型是某个特定类型或其子类型;下界通配符用于指定下界限制,表示参数化类型是某个特定类型或其父类型。
下面是使用通配符的一些示例代码:
-
上界通配符(? extends T):
// 定义一个泛型方法,用于打印列表中元素的值 public static void printList(List<? extends Number> list) { for (Number element : list) { System.out.println(element); } } // 使用上界通配符的示例 List<Integer> integerList = Arrays.asList(1, 2, 3); List<Double> doubleList = Arrays.asList(1.1, 2.2, 3.3); printList(integerList); // 可以接受Integer类型或其子类的列表 printList(doubleList); // 可以接受Double类型或其子类的列表
-
下界通配符(? super T):
// 定义一个泛型方法,用于添加数据到列表中 public static void addData(List<? super Integer> list, int data) { list.add(data); } // 使用下界通配符的示例 List<Number> numberList = new ArrayList<>(); addData(numberList, 10); // 可以接受Number类型或其父类的列表 List<Object> objectList = new ArrayList<>(); addData(objectList, 20); // 可以接受Object类型或其父类的列表
这些示例展示了使用通配符的情况,通过使用通配符,我们可以编写更加灵活的代码,能够处理不同范围的类型参数。需要注意的是,通配符只能用于方法参数或局部变量的定义中,不能用于类的声明或实例化。
通配符可以使用在泛型方法、泛型接口、泛型类等场景中,用于增加灵活性,使方法或类能够处理更广泛的数据类型。
-
泛型方法: 泛型方法是定义在类或接口中的方法,使用了泛型类型参数。泛型方法可以有自己独立的类型参数,也可以使用类或接口的类型参数。泛型方法通过在方法返回类型前面添加尖括号(<>)和类型参数来定义。
例如,定义一个泛型方法来比较两个对象的大小:
public <T extends Comparable<T>> int compare(T obj1, T obj2) { return obj1.compareTo(obj2); }
在调用泛型方法时,可以根据实际情况传入不同类型的参数。
-
泛型的嵌套使用: 泛型可以进行嵌套使用,即在泛型类或泛型方法中使用另一个泛型。在嵌套使用时,需要注意类型参数的声明和使用的一致性。
例如,定义一个嵌套泛型类:
public class MyGenericClass<T, K> { private T value; private K key; public void setValue(T value) { this.value = value; } public void setKey(K key) { this.key = key; } public T getValue() { return value; } public K getKey() { return key; } }
在使用嵌套泛型时,可以根据需要传入不同类型的参数,实现更灵活的数据处理。