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

Java泛型(超详细介绍)

 一、泛型

 什么是泛型?为什么要使用泛型?


泛型,即“参数化类型”。一提到参数,最熟悉的就是定义方法时有形参列表,普通方法的形参列表中,每个形参的数据类型是确定的,而变量是一个参数。在调用普通方法时需要传入对应形参数据类型的变量(实参),若传入的实参与形参定义的数据类型不匹配,则会报错。

参数化类型是什么?

以方法的定义为例,在方法定义时,将方法签名中的形参的数据类型也设置为参数(也可称之为类型参数),在调用该方法时再从外部传入一个具体的数据类型和变量。

泛型的本质是为了将类型参数化, 也就是说在泛型使用过程中,数据类型被设置为一个参数,在使用时再从外部传入一个数据类型;而一旦传入了具体的数据类型后,传入变量(实参)的数据类型如果不匹配,编译器就会直接报错。

这种参数化类型可以用在类、接口和方法中,分别被称为泛型类、泛型接口、泛型方法。

1.为什么要使用泛型,看下面程序存在的缺陷?

User类:

public class User {

    private String name;

    public User(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void pay(){
        System.out.println(this.name + "正在支付。。。");
    }

}
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

/**
 * 当前程序先不使用泛型,分析存在什么缺点?
 *      不好看,代码写的比较多。每一次从集合中取出的元素要想访问子类中特有的方法,必须向下转型。
 *      大部分都是要写向下转型的。因为Object类中的方法肯定是不够用的。一定会调用子类方法。
 */
public class GenericTest01 {
    public static void main(String[] args) {

        // 创建集合
        Collection c = new ArrayList();

        // 创建User类型的对象
        User u1 = new User("张三");
        User u2 = new User("李四");
        User u3 = new User("王五");

        // 添加到集合中
        c.add(u1);
        c.add(u2);
        c.add(u3);

        // 遍历集合
        Iterator it = c.iterator();
        while(it.hasNext()){
            Object obj = it.next();
            if(obj instanceof User) {
                // 支付
                // 这里没有使用泛型机制,那么要想调用pay()方法,必须进行向下转型
                User user = (User) obj;
                user.pay();
            }
        }

    }
}

2.泛型

User类:

public class User {

    private String name;

    public User(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void pay(){
        System.out.println(this.name + "正在支付。。。");
    }

}
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

/**
 * 使用泛型机制。
 */
public class GenericTest02 {
    public static void main(String[] args) {
        // 程序编写的时候,是否可以使用泛型,看哪里?
        // 看帮助文档中有没有“<>”符号。
        // 有这个符号的都可以使用泛型。
        // 创建一个集合,要求这个集合中只能存放User类型的对象。不能存储其他类型。
        //Collection<User> users = new ArrayList<User>();
        Collection<User> users = new ArrayList<>();

        // 向集合中添加User对象
        User u1 = new User("张三");
        User u2 = new User("李四");
        User u3 = new User("王五");
        users.add(u1);
        users.add(u2);
        users.add(u3);

        // 编译器报错,不能添加其他类型,只能添加User类型。
        //users.add("abc");

        // 遍历集合
        Iterator<User> it = users.iterator();
        while(it.hasNext()){
            User user = it.next();
            user.pay();
        }



    }
}

运行结果:

3.Java7的新特性:钻石表达式

< >里面的对象,写前面一个就行

Collection<String> strs = new ArrayList<>();

4.泛型的擦除与补偿(了解)

泛型的作用

  1. 编译时类型安全

    • 在编译阶段检查集合元素的类型,避免运行时出现 ClassCastException

  2. 代码可读性

    • 明确集合中元素的类型,减少类型转换代码。

⑴.泛型擦除(Type Erasure)(子类——>Object)

机制: 编译后擦除:泛型信息在编译后被移除,替换为 Object 类型(或泛型上限类型)。

示例:

List<String> list = new ArrayList<>();  
// 编译后变为 List<Object>  

原因:其本质是为了让JDK1.4和JDK1.5能够兼容同一个类加载器。在JDK1.5版本中,程序编译时期会对集合添加的元素进行安全检查,如果检查完是安全的、没有错误的,那么就意味着添加的元素都属于同一种数据类型,则加载类时就可以把这个泛型擦除掉,将泛型擦除后的类型就是Object类,这样擦除之后的代码就与JDK1.4的代码一致。

运行时无关性:泛型是编译时技术,JVM 不感知泛型。

由于加载类的时候,会默认将类中的泛型擦除为Object类型,所以添加的元素就被转化为Object类型,同时取出的元素也默认为Object类型。而我们获得集合中的元素时,按理说取出的元素应该是Object类型,为什么取出的元素却是实际添加的元素类型呢?

⑵.泛型补偿(Type Compensation)(Object——>子类)

机制: 运行时自动强转:从集合中取出元素时,JVM 根据元素的实际类型隐式执行强制类型转换。

示例:

List<String> list = new ArrayList<>();  
list.add("hello");  // 编译后变为 List<Object> 
String s = list.get(0); // 自动转换为 String,无需手动强转  

       这里又做了一个默认的操作,我们称之为泛型的补偿。在程序运行时,通过获取元素的实际类型进行强转,这就叫做泛型补偿(不必手动实现强制转换)。

       获得集合中的元素时,虚拟机会根据获得元素的实际类型进行向下转型(父转子),也就是会恢复获得元素的实际类型,因此我们就无需手动执行向下转型操作,从本质上避免了抛出类型转换异常。

意义:

开发者透明:无需手动写类型转换代码。

避免类型错误:编译时已确保类型安全,运行时不会抛出 ClassCastException。

阶段 泛型擦除 泛型补偿
时间 编译时 运行时
操作 泛型信息替换为 Object 隐式执行 Object → 实际类型 的转换
目的 兼容旧版本,简化 JVM 实现 恢复实际类型,保证代码逻辑正确性

5.泛型的使用:在类上定义泛型

⑴.泛型类基本概念

作用:让类可以处理多种数据类型,同时保

相关文章:

  • 树莓派 4B:AI 物联网完整部署方案
  • QT项目——天气预报
  • Qt QStackedWidget 总结
  • React 源码揭秘 | CompleteWork “归“的过程
  • Java 23新特性深度解析:开启下一代Java开发新范式
  • 深入解析:短轮询、长轮询、长连接与WebSocket(原理到实现)
  • 2025-arXiv-AlphaSharpe: LLM 驱动的稳健风险调整金融指标
  • python查错误TypeError: bad operand type for unary -: ‘str‘
  • Windows PyCharm的python项目移动存储位置后需要做的变更
  • Qt的QToolButton的使用
  • Java——super
  • 破解Docker镜像拉取难题:为Docker配置代理加速镜像拉取
  • 【JMeter使用-2】JMeter中Java Request采样器的使用指南
  • 【教学类-89-06】20250220新年篇05——元宵节灯笼
  • 机器学习实战:从理论到应用的完整指南
  • 优艾智合获批广东省复合协作机器人工程技术研究中心
  • 【C#】无法安装程序包“DotSpatial.Symbology 4.0.656”
  • jsherp importItemExcel接口存在SQL注入
  • uniapp多端适配
  • 【C语言】CreateFile函数用法介绍
  • 前瞻|中俄元首今年将首次面对面会晤,专家:国际变局中构建更坚韧的合作架构
  • 鸿蒙概念股强势上涨,鸿蒙电脑本月正式发布,生态链即将补全
  • 联合国秘书长古特雷斯呼吁印巴保持最大克制
  • 涉“子宫肌瘤”论文现55例男性对照观察患者?山大齐鲁医院:正在调查
  • 谢承祥已任自然资源部总工程师
  • 塞尔维亚总统因突发健康问题,中断对美国的正式访问并回国