Appearance
泛型
泛型是 Java 5 引入的特性,允许在定义类、接口和方法时使用类型参数。泛型提供了编译时类型安全检查,消除了大部分类型转换。
泛型概述
为什么需要泛型
java
import java.util.*;
public class WhyGenerics {
public static void main(String[] args) {
// 没有泛型时(Java 5 之前)
List list = new ArrayList();
list.add("Hello");
list.add(123); // 可以添加任意类型
String str = (String) list.get(0); // 需要强制类型转换
// String str2 = (String) list.get(1); // 运行时 ClassCastException
// 使用泛型
List<String> genericList = new ArrayList<>();
genericList.add("Hello");
// genericList.add(123); // 编译错误:类型检查
String genericStr = genericList.get(0); // 不需要类型转换
}
}泛型的优势
text
┌─────────────────────────────────────────────────────────────────┐
│ 泛型的优势 │
├─────────────────────────────────────────────────────────────────┤
│ 1. 类型安全:编译时检查类型,避免运行时类型转换异常 │
│ 2. 消除类型转换:不需要手动进行类型转换 │
│ 3. 代码复用:可以编写通用的代码,适用于多种类型 │
│ 4. 提高可读性:代码意图更加清晰 │
└─────────────────────────────────────────────────────────────────┘泛型类
定义泛型类
java
// 泛型类:类型参数 T
public class Box<T> {
private T content;
public Box() {
}
public Box(T content) {
this.content = content;
}
public T getContent() {
return content;
}
public void setContent(T content) {
this.content = content;
}
public static void main(String[] args) {
// 使用泛型类
Box<String> stringBox = new Box<>("Hello");
System.out.println("字符串盒子:" + stringBox.getContent());
Box<Integer> integerBox = new Box<>(100);
System.out.println("整数盒子:" + integerBox.getContent());
Box<Double> doubleBox = new Box<>(3.14);
System.out.println("浮点数盒子:" + doubleBox.getContent());
}
}多个类型参数
java
// 多个类型参数
public 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;
}
@Override
public String toString() {
return "(" + key + ", " + value + ")";
}
public static void main(String[] args) {
Pair<String, Integer> nameAge = new Pair<>("张三", 25);
System.out.println("姓名-年龄:" + nameAge);
Pair<String, String> capital = new Pair<>("中国", "北京");
System.out.println("国家-首都:" + capital);
}
}泛型接口
定义泛型接口
java
// 泛型接口
interface Container<T> {
void add(T item);
T get(int index);
int size();
}
// 实现泛型接口:指定具体类型
class StringContainer implements Container<String> {
private List<String> items = new ArrayList<>();
@Override
public void add(String item) {
items.add(item);
}
@Override
public String get(int index) {
return items.get(index);
}
@Override
public int size() {
return items.size();
}
}
// 实现泛型接口:保留泛型
class GenericContainer<T> implements Container<T> {
private List<T> items = new ArrayList<>();
@Override
public void add(T item) {
items.add(item);
}
@Override
public T get(int index) {
return items.get(index);
}
@Override
public int size() {
return items.size();
}
}
public class GenericInterfaceDemo {
public static void main(String[] args) {
Container<String> stringContainer = new StringContainer();
stringContainer.add("Hello");
System.out.println(stringContainer.get(0));
Container<Integer> intContainer = new GenericContainer<>();
intContainer.add(100);
System.out.println(intContainer.get(0));
}
}泛型方法
定义泛型方法
java
import java.util.Arrays;
public class GenericMethod {
public static void main(String[] args) {
// 调用泛型方法
Integer[] intArray = {1, 2, 3, 4, 5};
String[] strArray = {"A", "B", "C"};
printArray(intArray);
printArray(strArray);
// 泛型方法返回值
Integer max = findMax(intArray);
System.out.println("最大值:" + max);
// 泛型方法与类型推断
String middle = getMiddle(strArray);
System.out.println("中间元素:" + middle);
}
// 泛型方法:<T> 放在返回值类型之前
public static <T> void printArray(T[] array) {
for (T item : array) {
System.out.print(item + " ");
}
System.out.println();
}
// 泛型方法带返回值
public static <T extends Comparable<T>> T findMax(T[] array) {
if (array == null || array.length == 0) {
return null;
}
T max = array[0];
for (int i = 1; i < array.length; i++) {
if (array[i].compareTo(max) > 0) {
max = array[i];
}
}
return max;
}
// 泛型方法
public static <T> T getMiddle(T[] array) {
return array[array.length / 2];
}
// 非泛型类中的泛型方法
public static <K, V> void printPair(K key, V value) {
System.out.println("Key: " + key + ", Value: " + value);
}
}泛型方法与泛型类
java
public class GenericMethodVsClass<T> {
private T value;
// 泛型类的方法(使用类的类型参数)
public void setValue(T value) {
this.value = value;
}
// 泛型方法(使用自己的类型参数)
public static <E> void print(E item) {
System.out.println(item);
}
// 泛型方法(与类的类型参数不同)
public <E> void process(E item) {
System.out.println("处理:" + item);
}
public static void main(String[] args) {
GenericMethodVsClass<String> obj = new GenericMethodVsClass<>();
obj.setValue("Hello"); // T = String
GenericMethodVsClass.print(123); // E = Integer
obj.process(3.14); // E = Double
}
}类型通配符
无界通配符
java
import java.util.*;
public class UnboundedWildcard {
public static void main(String[] args) {
List<String> strings = Arrays.asList("A", "B", "C");
List<Integer> integers = Arrays.asList(1, 2, 3);
printList(strings);
printList(integers);
}
// 无界通配符:可以接受任何类型
public static void printList(List<?> list) {
for (Object item : list) {
System.out.print(item + " ");
}
System.out.println();
// list.add("new"); // 编译错误:不能添加元素(除了 null)
Object obj = list.get(0); // 可以读取,类型为 Object
}
}上界通配符
java
import java.util.*;
public class UpperBoundedWildcard {
public static void main(String[] args) {
List<Integer> integers = Arrays.asList(1, 2, 3, 4, 5);
List<Double> doubles = Arrays.asList(1.5, 2.5, 3.5);
List<Number> numbers = Arrays.asList(10, 20.5, 30);
System.out.println("Integer 和:" + sum(integers));
System.out.println("Double 和:" + sum(doubles));
System.out.println("Number 和:" + sum(numbers));
}
// 上界通配符:接受 Number 或其子类
public static double sum(List<? extends Number> list) {
double total = 0;
for (Number num : list) {
total += num.doubleValue();
}
// list.add(10); // 编译错误:不能添加元素
// 因为不知道具体是 Integer、Double 还是其他子类
return total;
}
}下界通配符
java
import java.util.*;
public class LowerBoundedWildcard {
public static void main(String[] args) {
List<Integer> integers = new ArrayList<>();
List<Number> numbers = new ArrayList<>();
List<Object> objects = new ArrayList<>();
addNumbers(integers); // 可以添加 Integer 及其父类
addNumbers(numbers);
addNumbers(objects);
System.out.println("integers: " + integers);
System.out.println("numbers: " + numbers);
System.out.println("objects: " + objects);
}
// 下界通配符:接受 Integer 或其父类
public static void addNumbers(List<? super Integer> list) {
list.add(1);
list.add(2);
list.add(3);
// Integer i = list.get(0); // 编译错误:读取的类型不确定
Object obj = list.get(0); // 只能作为 Object 读取
}
}PECS 原则
text
┌─────────────────────────────────────────────────────────────────┐
│ PECS 原则 │
├─────────────────────────────────────────────────────────────────┤
│ Producer Extends, Consumer Super │
│ │
│ 如果需要从集合中读取数据(生产者),使用 ? extends T │
│ 如果需要向集合中写入数据(消费者),使用 ? super T │
│ 如果既要读又要写,使用精确的类型 T │
│ │
│ 示例: │
│ public static <T> void copy( │
│ List<? super T> dest, // 消费者:写入数据 │
│ List<? extends T> src // 生产者:读取数据 │
│ ) { │
│ for (T item : src) { │
│ dest.add(item); │
│ } │
│ } │
└─────────────────────────────────────────────────────────────────┘类型擦除
泛型的实现原理
java
import java.util.*;
public class TypeErasure {
public static void main(String[] args) {
// 泛型类型在编译时被擦除
List<String> strings = new ArrayList<>();
List<Integer> integers = new ArrayList<>();
// 运行时类型相同
System.out.println(strings.getClass() == integers.getClass()); // true
System.out.println(strings.getClass().getName()); // java.util.ArrayList
// 泛型信息在运行时不可用
// if (strings instanceof List<String>) { } // 编译错误
if (strings instanceof List) { } // 正确
}
}类型擦除规则
text
┌─────────────────────────────────────────────────────────────────┐
│ 类型擦除规则 │
├─────────────────────────────────────────────────────────────────┤
│ 1. 无界类型参数(<T>)擦除为 Object │
│ 2. 有界类型参数(<T extends Number>)擦除为边界类型 Number │
│ 3. 多个边界取第一个边界类型 │
│ 4. 泛型方法中的类型参数同样被擦除 │
│ 5. 桥方法用于保持多态性 │
└─────────────────────────────────────────────────────────────────┘java
// 编译前
class GenericClass<T extends Number> {
private T value;
public T getValue() {
return value;
}
public void setValue(T value) {
this.value = value;
}
}
// 编译后(类型擦除)
class GenericClass {
private Number value;
public Number getValue() {
return value;
}
public void setValue(Number value) {
this.value = value;
}
}泛型限制
不能使用的场景
java
import java.util.*;
public class GenericLimitations {
public static void main(String[] args) {
// 1. 不能实例化类型参数
// T item = new T(); // 编译错误
// 2. 不能创建泛型数组
// T[] array = new T[10]; // 编译错误
// List<String>[] array = new List<String>[10]; // 编译错误
// 正确的方式
List<?>[] array = new List<?>[10];
@SuppressWarnings("unchecked")
List<String>[] stringLists = (List<String>[]) new List[10];
// 3. 不能使用基本类型
// List<int> intList = new ArrayList<>(); // 编译错误
List<Integer> intList = new ArrayList<>(); // 使用包装类
// 4. 不能抛出或捕获泛型类异常
// class MyException<T> extends Exception { } // 编译错误
// 5. 不能重载具有相同擦除类型的方法
// public void method(List<String> list) { }
// public void method(List<Integer> list) { } // 编译错误
}
// 使用反射创建泛型数组
@SuppressWarnings("unchecked")
public static <T> T[] createArray(Class<T> type, int size) {
return (T[]) java.lang.reflect.Array.newInstance(type, size);
}
}泛型最佳实践
命名约定
java
// 泛型类型参数命名约定
public class NamingConventions {
// T - Type(类型)
public static <T> void process(T item) { }
// E - Element(元素,常用于集合)
public static <E> void addToCollection(Collection<E> collection, E element) { }
// K - Key(键)
// V - Value(值)
public static <K, V> void putToMap(Map<K, V> map, K key, V value) { }
// N - Number(数字)
public static <N extends Number> double doubleValue(N number) {
return number.doubleValue();
}
// R - Result(结果)
// S, U, V 等 - 多个类型参数
public static <S, T> Pair<S, T> createPair(S first, T second) {
return new Pair<>(first, second);
}
}泛型工具方法
java
import java.util.*;
public class GenericUtils {
// 交换数组元素
public static <T> void swap(T[] array, int i, int j) {
T temp = array[i];
array[i] = array[j];
array[j] = temp;
}
// 查找元素
public static <T> int indexOf(T[] array, T target) {
for (int i = 0; i < array.length; i++) {
if (array[i].equals(target)) {
return i;
}
}
return -1;
}
// 过滤集合
public static <T> List<T> filter(List<T> list, Predicate<T> predicate) {
List<T> result = new ArrayList<>();
for (T item : list) {
if (predicate.test(item)) {
result.add(item);
}
}
return result;
}
// 映射集合
public static <T, R> List<R> map(List<T> list, Function<T, R> mapper) {
List<R> result = new ArrayList<>();
for (T item : list) {
result.add(mapper.apply(item));
}
return result;
}
@FunctionalInterface
interface Predicate<T> {
boolean test(T t);
}
@FunctionalInterface
interface Function<T, R> {
R apply(T t);
}
public static void main(String[] args) {
Integer[] numbers = {1, 2, 3, 4, 5};
swap(numbers, 0, 4);
System.out.println("交换后:" + Arrays.toString(numbers));
String[] names = {"张三", "李四", "王五"};
System.out.println("李四的索引:" + indexOf(names, "李四"));
List<Integer> nums = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
List<Integer> evens = filter(nums, n -> n % 2 == 0);
System.out.println("偶数:" + evens);
List<String> nameList = Arrays.asList("张三", "李四", "王五");
List<Integer> lengths = map(nameList, String::length);
System.out.println("名字长度:" + lengths);
}
}小结
本章我们学习了:
- 泛型概述:类型安全、消除类型转换
- 泛型类:定义和使用泛型类
- 泛型接口:实现泛型接口
- 泛型方法:定义和使用泛型方法
- 类型通配符:无界、上界、下界通配符
- PECS 原则:Producer Extends, Consumer Super
- 类型擦除:泛型的实现原理
- 泛型限制:不能使用的场景
下一章,我们将学习 注解,了解 Java 注解的使用。
