Java 泛型(Generic)
Java 泛型(Generic)
一、理论说明
1. 泛型的定义
Java 泛型是 JDK 5.0 引入的一项特性,它提供了一种参数化类型的机制,允许在定义类、接口或方法时使用类型参数。通过泛型,开发者可以编写更加通用、类型安全的代码,减少强制类型转换,提高代码的可读性和可维护性。泛型的本质是类型参数化,即把类型作为参数传递,使得类、接口或方法能够处理多种不同类型的数据,同时保持编译时的类型安全。
2. 泛型与普通类的区别
- 类型安全性:
- 普通类在处理不同类型的数据时,通常需要进行强制类型转换,这可能会在运行时导致
ClassCastException
异常。例如,使用普通的ArrayList
存储不同类型的元素,在取出元素时需要进行类型转换。 - 泛型类在定义时就指定了具体的类型参数,编译器会在编译时进行类型检查,确保只能存储指定类型的元素,从而避免了运行时的类型转换异常。例如,
ArrayList<String>
只能存储String
类型的元素,在编译时就会对不匹配的类型进行错误提示。
- 普通类在处理不同类型的数据时,通常需要进行强制类型转换,这可能会在运行时导致
- 代码复用性:
- 普通类需要为不同的数据类型编写重复的代码,例如,为处理
Integer
类型和String
类型的数据,可能需要编写两个几乎相同的类。 - 泛型类通过类型参数可以处理多种不同类型的数据,实现了代码的复用。例如,
ArrayList<E>
可以处理任意类型的数据,只需要在使用时指定具体的类型参数。
- 普通类需要为不同的数据类型编写重复的代码,例如,为处理
- 编程效率:
- 使用普通类时,由于需要进行强制类型转换,代码会变得冗长,并且容易出错。
- 泛型类消除了强制类型转换,使代码更加简洁、清晰,提高了编程效率。
二、常用语法与示例
1. 泛型类
泛型类是在类名后面添加类型参数声明,使用尖括号<>
括起来,可以有一个或多个类型参数,多个参数之间用逗号分隔。例如:
public class Box<T> {private T content;public void setContent(T content) {this.content = content;}public T getContent() {return content;}
}
2. 泛型方法
泛型方法是在方法返回类型前添加类型参数声明,使用尖括号<>
括起来。泛型方法可以在普通类中定义,也可以在泛型类中定义。例如:
public class GenericMethodExample {public static <T> void printArray(T[] array) {for (T element : array) {System.out.print(element + " ");}System.out.println();}public static void main(String[] args) {Integer[] intArray = {1, 2, 3, 4, 5};String[] stringArray = {"Hello", "World"};printArray(intArray);printArray(stringArray);}
}
3. 泛型接口
泛型接口的定义与泛型类类似,在接口名后面添加类型参数声明。例如:
public interface Generator<T> {T generate();
}public class StringGenerator implements Generator<String> {@Overridepublic String generate() {return "Generated String";}
}
4. 通配符
通配符?
用于表示未知类型,主要有三种形式:
四、面试题
题目:
答案:
五、自我总结
通过对 Java 泛型的学习,我们掌握了一种强大的类型参数化机制。与普通类相比,泛型类在类型安全性、代码复用性和编程效率方面具有明显优势。掌握泛型类、泛型方法、泛型接口和通配符的使用,能够让我们在实际编程中编写更加通用、类型安全的代码。在实际应用场景中,如集合框架、数据处理、设计模式等方面,泛型都能发挥重要作用。合理使用泛型可以避免类型转换异常,提高代码的可读性和可维护性,是 Java 编程中不可或缺的一项重要技术。
- 无界通配符:
<?>
,表示未知类型。例如:public static void printList(List<?> list) {for (Object element : list) {System.out.print(element + " ");}System.out.println(); }
- 上界通配符:
<? extends T>
,表示类型必须是T
或T
的子类。例如:public static double sumOfList(List<? extends Number> list) {double sum = 0.0;for (Number n : list) {sum += n.doubleValue();}return sum; }
- 下界通配符:
<? super T>
,表示类型必须是T
或T
的父类。例如:public static void addNumbers(List<? super Integer> list) {for (int i = 1; i <= 10; i++) {list.add(i);} }
三、应用实例
以下代码展示了泛型的综合应用:
import java.util.ArrayList; import java.util.List;// 泛型类:容器 class Container<T> {private List<T> items;public Container() {this.items = new ArrayList<>();}public void addItem(T item) {items.add(item);}public T getItem(int index) {return items.get(index);}public int size() {return items.size();}// 泛型方法:交换容器中两个元素的位置public <E> void swap(int i, int j) {if (i < 0 || i >= size() || j < 0 || j >= size()) {throw new IndexOutOfBoundsException("索引超出范围");}T temp = items.get(i);items.set(i, items.get(j));items.set(j, temp);}// 使用上界通配符的方法:计算容器中所有元素的和(假设元素是Number或其子类)public double sum() {double sum = 0.0;for (T item : items) {if (item instanceof Number) {sum += ((Number) item).doubleValue();}}return sum;} }public class Main {public static void main(String[] args) {// 创建一个存储整数的容器Container<Integer> intContainer = new Container<>();intContainer.addItem(10);intContainer.addItem(20);intContainer.addItem(30);System.out.println("交换前的容器元素:");for (int i = 0; i < intContainer.size(); i++) {System.out.print(intContainer.getItem(i) + " ");}System.out.println();// 交换元素位置intContainer.swap(0, 2);System.out.println("交换后的容器元素:");for (int i = 0; i < intContainer.size(); i++) {System.out.print(intContainer.getItem(i) + " ");}System.out.println();// 计算元素的和double sum = intContainer.sum();System.out.println("元素的和: " + sum);// 创建一个存储字符串的容器Container<String> stringContainer = new Container<>();stringContainer.addItem("Hello");stringContainer.addItem("World");System.out.println("字符串容器的元素:");for (int i = 0; i < stringContainer.size(); i++) {System.out.print(stringContainer.getItem(i) + " ");}System.out.println();} }
代码解释
- 泛型类定义:
Container<T>
是一个泛型类,使用类型参数T
,内部使用List<T>
存储元素,提供了添加元素、获取元素、交换元素位置和计算元素和等方法。 - 泛型方法实现:
swap
方法是一个泛型方法,用于交换容器中两个元素的位置,通过类型参数<E>
实现了更灵活的类型检查。 - 通配符使用:
sum
方法使用了上界通配符<? extends Number>
,确保只能处理Number
或其子类类型的元素,从而实现了对数值类型元素的求和操作。