当前位置: 首页 > news >正文

Java核心之泛型

Java 泛型(Generics)是 JDK 5 引入的特性,它允许在定义类、接口和方法时使用类型参数(type parameter),从而实现代码的类型安全复用性。泛型的核心思想是 “参数化类型”,即把类型作为参数传递。

一、泛型的基本概念

在泛型出现之前,Java 集合只能存储 Object 类型,取出时需要强制类型转换,容易出现 ClassCastException。泛型通过在编译期检查类型,避免了运行时的类型转换错误。

示例:无泛型 vs 有泛型

// 无泛型:需要强制转换,可能出错
List list = new ArrayList();
list.add("hello");
String str = (String) list.get(0); // 正确
Integer num = (Integer) list.get(0); // 运行时抛 ClassCastException// 有泛型:编译期检查类型,无需强制转换
List<String> strList = new ArrayList<>();
strList.add("hello");
String str = strList.get(0); // 无需转换,安全
strList.add(123); // 编译期报错(类型不匹配)

二、泛型的使用场景

泛型主要用于类、接口、方法的定义,分别称为泛型类泛型接口泛型方法

1. 泛型类

在类定义时声明类型参数,使用 <T>(T 为类型变量,可自定义名称,如 E、K、V 等)表示。

示例:自定义泛型类

// 泛型类:T 为类型参数(Type Parameter)
public class Box<T> {private T value;public void setValue(T value) {this.value = value;}public T getValue() {return value;}public static void main(String[] args) {// 使用时指定具体类型(Type Argument)Box<String> stringBox = new Box<>();stringBox.setValue("Hello");String str = stringBox.getValue(); // 类型安全Box<Integer> intBox = new Box<>();intBox.setValue(123);Integer num = intBox.getValue();}
}
  • 类型变量 T 在创建对象时被具体类型(如 StringInteger)替换。
  • 一个泛型类可以有多个类型参数,如 Map<K, V>(Key 和 Value 分别为两个类型参数)。
2. 泛型接口

与泛型类类似,接口定义时声明类型参数,实现类需指定具体类型或继续保留泛型。

示例:泛型接口

// 泛型接口
public interface Generator<T> {T generate();
}// 实现类:指定具体类型(String)
public class StringGenerator implements Generator<String> {@Overridepublic String generate() {return "Generated string";}
}// 实现类:保留泛型(适用于通用实现)
public class DefaultGenerator<T> implements Generator<T> {@Overridepublic T generate() {return null; // 简化示例}
}
3. 泛型方法

在方法声明时独立声明类型参数(与类的泛型无关),可以是静态方法或实例方法。

示例:泛型方法

public class GenericMethodExample {// 泛型方法:<T> 声明类型参数,T 为返回值类型public static <T> T getFirstElement(List<T> list) {if (list != null && !list.isEmpty()) {return list.get(0);}return null;}public static void main(String[] args) {List<String> strList = Arrays.asList("a", "b", "c");String firstStr = getFirstElement(strList); // 自动推断类型为 StringList<Integer> intList = Arrays.asList(1, 2, 3);Integer firstInt = getFirstElement(intList); // 自动推断类型为 Integer}
}
  • 泛型方法的类型参数声明 <T> 必须在返回值类型之前。
  • 调用时无需显式指定类型(编译器会自动推断)。

三、泛型通配符

泛型通配符(Wildcard)用于灵活处理泛型类型,常见的有 ?(无界通配符)、? extends T(上界通配符)、? super T(下界通配符)。

1. 无界通配符 ?

表示 “任意类型”,用于不确定具体类型的场景。

示例:

public static void printList(List<?> list) {for (Object obj : list) {System.out.println(obj);}
}// 可接收任意类型的 List
printList(Arrays.asList("a", "b"));
printList(Arrays.asList(1, 2, 3));
  • 注意:List<?> 不能添加元素(除了 null),因为编译器无法确定具体类型。
2. 上界通配符 ? extends T

表示 “T 及其子类”,限制类型的上限。

示例:

// 只能接收 Number 及其子类(如 Integer、Double)
public static double sum(List<? extends Number> numbers) {double total = 0;for (Number num : numbers) {total += num.doubleValue();}return total;
}// 合法调用
sum(Arrays.asList(1, 2, 3)); // Integer 是 Number 子类
sum(Arrays.asList(1.5, 2.5)); // Double 是 Number 子类
  • 上界通配符的集合只能读取(可安全转型为 T),不能添加(无法确定具体子类类型)。
3. 下界通配符 ? super T

表示 “T 及其父类”,限制类型的下限。

示例:

// 只能接收 Integer 及其父类(如 Number、Object)
public static void addIntegers(List<? super Integer> list) {list.add(1); // 可以添加 Integer 及其子类list.add(2);
}// 合法调用
addIntegers(new ArrayList<Integer>()); // Integer 本身
addIntegers(new ArrayList<Number>()); // Number 是 Integer 父类
  • 下界通配符的集合可以添加T 及其子类),读取时只能转型为 Object(无法确定具体父类类型)。

四、泛型擦除(Type Erasure)

Java 泛型是编译期特性,在编译后会被 “擦除”,字节码中不保留泛型类型信息,这一过程称为 “泛型擦除”。

  • 擦除规则:
    • 未指定边界的类型参数(如 <T>)擦除为 Object
    • 指定上界的类型参数(如 <T extends Number>)擦除为上界类型(Number)。

示例:擦除前后对比

// 泛型类(编译前)
public class Box<T> {private T value;public T getValue() { return value; }
}// 擦除后(编译为字节码)
public class Box {private Object value;public Object getValue() { return value; }
}
  • 泛型擦除导致运行时无法获取泛型类型信息(如 list.getClass() 只能得到 ArrayList.class,而非 ArrayList<String>.class)。
  • 这也是泛型数组创建受限的原因(new ArrayList<String>[10] 编译报错)。

五、泛型的限制

  1. 不能用基本类型实例化泛型:泛型类型参数必须是引用类型,如 List<int> 不合法,需用 List<Integer>
  2. 泛型类不能直接实例化类型参数:如 new T() 不合法(擦除后为 new Object(),失去意义)。
  3. 不能声明静态泛型字段:静态成员属于类,而泛型类型参数随实例变化。
  4. 泛型类不能扩展 Throwable:如 class MyException<T> extends Exception 不合法(异常处理需要确定的类型)。

六、泛型的优势

  1. 类型安全:编译期检查类型,避免运行时 ClassCastException
  2. 代码复用:一套代码可适配多种类型(如 ArrayList 可存储任意类型)。
  3. 可读性:代码中明确指定类型,无需注释即可知晓集合存储的元素类型。

总结

泛型通过参数化类型实现了类型安全和代码复用,是 Java 集合框架、框架开发(如 Spring、MyBatis)的基础。掌握泛型的核心概念(泛型类、接口、方法)和通配符的使用,能写出更健壮、灵活的代码。尽管泛型擦除带来了一些限制,但仍是 Java 中不可或缺的重要特性。

http://www.dtcms.com/a/403581.html

相关文章:

  • 直播进入“智”时代!智享 AI 驱动个性化内容,升级高效互动场景
  • 河南襄县做网站的公司查企业官网
  • Linux:fork()函数详解:原理、用法及经典面试题解析
  • tensorflow卷积层1——卷积和池化
  • tensorflow加载和预处理数据
  • DAY 03 CSS的认识
  • 黑群晖做php网站pc网站手机网站
  • Jakarta EE 实验 — Web 聊天室(过滤器、监听器版)
  • 做js题目的网站知乎抖音代运营公司合法吗
  • MyBatis的最佳搭档(MyBatis-Plus)
  • 无用知识研究:和普通函数不同,返回类型也参与了模板函数的signature
  • 简单小结类与对象
  • Java 大视界 -- Java 大数据机器学习模型在金融风险传染路径分析与防控策略制定中的应用
  • 【C++】Template:深入理解特化与分离编译,破解编译难题
  • 【把15v方波转为±7.5v的方波】2022-12-21
  • 自己可以做一个网站吗自己怎么做直播网站吗
  • 嵌入式开发常见问题解决:Keil头文件路径与MCUXpresso外设配置错误
  • 从Android到iOS:启动监控实现的跨平台技术对比
  • 数据开放网站建设内容大连可以做网站的公司
  • lesson67:JavaScript事件绑定全解析:从基础到高级实践
  • 软件开发还是网站开发好惠州seo招聘
  • ARM芯片架构之CoreSight系统架构规范
  • 品牌网站建设黑白I狼J足球比赛直播网
  • 支持向量机深度解析:从数学原理到工程实践的完整指南——核技巧与凸优化视角下的模式识别革命
  • FPGA有什么作用和功能,主副关系是什么,跟通道有什么关系
  • 怎么做整蛊网站dw自己做的网站手机进不去
  • Udp 和 Tcp socket的一般编程套路(笔记)
  • C++_STL和数据结构《3》_仿函数作为STL中算法参数的用法、匿名函数、序列容器使用、关联容器使用、无关联容器使用、容器适配器使用
  • php基础-流程控制(第12天)
  • 怎样建设尧都水果网站网页游戏网站556pk游戏福利平台