Java泛型(Generics)是Java语言中一种类型参数化
的机制,允许在类、接口、方法
中使用类型参数,使代码能够处理多种数据类型,同时保证类型安全。泛型的主要目的是增强代码的复用性
和安全性
,避免类型转换错误。
泛型的核心概念
-
类型参数化
在定义类、接口或方法时,用<T>、<K,V>
等形式声明类型参数,实际使用时再指定具体类型。java">// 泛型类 public class Box<T> {private T content;public void setContent(T content) { this.content = content; }public T getContent() { return content; } }// 使用 Box<String> stringBox = new Box<>(); stringBox.setContent("Hello"); String value = stringBox.getContent(); // 无需强制类型转换
-
类型安全
编译器会检查泛型类型的合法性,防止在集合中混入不兼容的类型。java">List<String> list = new ArrayList<>(); list.add("Java"); // list.add(100); // 编译报错:类型不匹配
泛型的作用
-
类型安全(Type Safety)
在编译阶段进行类型检查,避免运行时出现ClassCastException
。java">// 不使用泛型(存在风险) List list = new ArrayList(); list.add("Java"); list.add(100); // 编译通过,但运行时会出错 String s = (String) list.get(1); // 运行时抛出ClassCastException// 使用泛型(类型安全) List<String> safeList = new ArrayList<>(); safeList.add("Java"); // safeList.add(100); // 编译直接报错
-
消除强制类型转换
从集合中获取元素时,无需显式强制转换。java">List<String> names = new ArrayList<>(); names.add("Alice"); String name = names.get(0); // 直接返回String类型
-
代码复用
通过泛型类、泛型方法,编写可处理多种类型的通用代码。java">public static <T> T getFirstElement(List<T> list) {return list.get(0); } // 支持任何类型的List String s = getFirstElement(Arrays.asList("A", "B")); Integer n = getFirstElement(Arrays.asList(1, 2));
-
增强可读性
泛型让代码的意图更明确。例如,Map<String, Integer>直接表明键是String,值是Integer。
泛型的核心特性
-
类型擦除(Type Erasure)
Java泛型在编译后会被擦除,转换为原始类型(Raw Type),并在必要时插入强制类型转换。java">// 编译前 List<String> list = new ArrayList<>(); // 编译后(类型擦除) List list = new ArrayList();
-
通配符(Wildcards)
(1)使用?表示未知类型,解决泛型类型的灵活性问题。
(2)上界通配符(<? extends T>):接受T及其子类。
(3)下界通配符(<? super T>):接受T及其父类。java">// 上界通配符:可以读取,不能写入 List<? extends Number> numbers = new ArrayList<Integer>(); Number num = numbers.get(0); // 允许读取 // numbers.add(10); // 编译报错// 下界通配符:可以写入,读取为Object List<? super Integer> list = new ArrayList<Number>(); list.add(100); // 允许写入 Object obj = list.get(0); // 读取为Object
-
泛型边界(Bounded Type)
通过 “T extends SomeClass” 限制泛型类型的范围。java">public class Calculator<T extends Number> {public double sum(T a, T b) {return a.doubleValue() + b.doubleValue();} } // 只能使用Number及其子类(如Integer、Double) Calculator<Integer> intCalc = new Calculator<>();
泛型的典型应用场景
-
集合框架(Collections)
List、Map<K,V>等集合类均使用泛型,确保元素类型安全。java">Map<String, Integer> scores = new HashMap<>(); scores.put("Alice", 90);
-
工具类(如Optional)
包装可能为空的值,避免NullPointerException。java">Optional<String> name = Optional.ofNullable(getName());
-
函数式接口(如Function<T,R>)
支持泛型参数和返回值,用于Lambda表达式。java">Function<Integer, String> intToString = num -> "Value: " + num;
注意事项
-
泛型不支持基本类型
必须使用包装类(如List<Integer>
,而非List<int>
)。 -
类型擦除的限制
无法在运行时获取泛型类型信息(如new T()或T.class)。 -
泛型数组的创建
直接创建泛型数组是非法的,需通过反射或强制转换。
总结
Java泛型通过类型参数化
,提供了一种类型安全的编程方式,避免了强制类型转换的繁琐和潜在错误,同时提升了代码的可读性和复用性。尽管存在类型擦除等限制,泛型仍是Java开发中不可或缺的核心特性。