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

泛型的相关知识

定义类、接口、方法时,同时声明了一个或多个类型变量(如:<E>),称为泛型类、泛型接口、泛型方法,他们统称为泛型

public class ArrayList<E>{ //... }

作用:泛型提供了在编译阶段约束所能操作的数据类型,并自动进行检查的能力,这样可以避免强制类型转换,及其可能出现的异常。

泛型的本质:把具体的数据类型作为参数传递给类型变量。

为什么要使用泛型

先来看我们不使用泛型时往集合中添加元素有什么问题

import java.util.ArrayList; import java.util.Iterator; public class Test { public static void main(String[] args) { //1.创建集合的对象 ArrayList list = new ArrayList(); //2.添加数据 list.add(123); list.add("aaa"); list.add(new Student("zhangsan", 21)); //3.遍历集合,获取里面的每一个元素 Iterator it = list.iterator(); while (it.hasNext()) { Object obj = it.next(); System.out.println(obj); } } }

输出结果:

当你往ArrayList集合中添加数据时,调用add()方法,会显示添加的数据是Object类型,也就是什么类型都可以添加,比如int类型、String类型,甚至是自己定义的Student类型,使用iterator()迭代器遍历集合中的元素,用next()方法拿到的元素也是Object类型的,我们可以将其打印输出,没有问题。但是,多态的弊端是不能访问子类特有的功能,比如我想打印输出第二个元素"aaa"的长度,这是一个String类型的数据,直接使用obj.length()来输出长度,但其实这样写是会报错的,编译就不通过

那如果强制转换

你会发现编译通过了,语法没有问题,但是运行会报错。

报了一个类型转换异常,为什么会报这个异常呢?

如果你是int类型转成String类型那没问题,但是遍历的是数组中的整个元素,自定义的Student类型怎么转成String类型呢,所以会报一个类型转换异常。

通过以上现象我们发现,当往集合中添加任意类型元素时,不能访问子类特有的功能,如果使用强制类型转换则可能会出现类型转换异常,所以使用泛型来解决这个问题。

import java.util.ArrayList; import java.util.Iterator; public class Test { public static void main(String[] args) { //1.创建集合的对象 ArrayList<String> list = new ArrayList(); //2.添加数据 // list.add(123); list.add("aaa"); list.add("bbb"); list.add("ccc"); // list.add(new Student("zhangsan", 21)); //3.遍历集合,获取里面的每一个元素 Iterator<String> it = list.iterator(); while (it.hasNext()) { String str = it.next(); System.out.println(str); } } }

使用泛型<String>来规定ArrayList数组中的数据类型只能是String类型,这样就保证了数组中数据类型的统一,把运行时期的问题提前到了编译时期,避免了强制类型转换可能出现的异常。

泛型的分类

前面提到,在定义类、接口、方法时,同时声明了一个或多个类型变量(如:<E>),称为泛型类、泛型接口、泛型方法,泛型也就分为这三类,每类都各自有各自的格式。

泛型类

格式:

修饰符 class 类名<类型变量,类型变量,...> {

}

public class ArrayList<E>{ ... }

类型变量建议用大写的英文字母,常用的有:E、T、K、V

自定义泛型类

自定义泛型类——声明单个

public class MyArrayList<E> { private Object[] arr = new Object[10]; private int size;//记录当前位置的 public boolean add(E e){ arr[size++] = e; return true; } public E get(int index){ return (E) arr[index]; } }

自定义泛型类——声明多个

public class MyClass1<E, T> { public void put(E e, T t){ } }

自定义泛型类——必须要继承某个类

public class MyClass2<E extends Animal> { }

泛型接口

格式:

修饰符 interface 接口名<类型变量, 类型变量, ...>{
}

public interface A<E> { ... }

举例:

public interface Data<T> { void add(T t); ArrayList<T> getByName(String name); }

泛型方法

格式:

修饰符 <类型变量, 类型变量, ...> 返回值类型 方法名(形参列表) {

}

public static <T> void test(T t) { }

注意这个下面这个不是泛型方法:

public E get(int index) { return (E) arr[index]; }

补充知识

拓展知识:

当你在java文件中使用了泛型来限制数据类型,但当这个java文件编译成class文件后就没有你写的泛型了,统一当成Object类型处理,只是当你往外取数据时,底层会帮你再次强转成你所定义的泛型。

泛型的细节:

  1. 泛型是工作在编译阶段的,一旦程序编译成class文件,class文件中就不存在泛型了,这叫做泛型擦除
  2. 泛型不支持基本数据类型,只能支持对象类型(引用数据类型)。
  3. 指定泛型的具体数据类型后,传递数据时,可以传入该类类型或者其子类类型
  4. 如果不写泛型,默认是Object类型

通配符

就是“?”,可以在“使用泛型”的时候代表一切类型;

E T K V是在定义泛型的时候使用。

泛型的上下限

泛型上限:? extends A:?能接收的必须是A或者是A的子类

泛型下线:? super A:?能接收的必须是A或者是A的父类

http://www.jsqmd.com/news/84272/

相关文章:

  • java流程控制
  • 2025年降AI率工具实测!5个降AI工具推荐:免费降AIGC工具指南
  • Halo博客系统审计
  • 2025免费降AI率完全指南:从查AI工具选择到降AI技巧,一步到位!
  • 终极指南:快速搭建Gitea自托管Git服务
  • 数字电路模拟程序课堂测验-总结
  • tk.simpledialog-创建简单的模态对话框
  • STranslate 翻译 工具 v2.0.0 绿色便携版 翻译、OCR工具
  • 终极指南:免费获取卓里奇数学分析教材PDF完整资源
  • 毕业设计实战:基于SpringBoot+MySQL的毕业生实习与就业管理系统设计与实现,从需求到测试全流程避坑指南!
  • Pyperclip终极指南:3分钟掌握Python跨平台剪贴板操作
  • 毕业设计实战:基于SSM+MySQL的校园外卖服务系统设计与实现,从需求到上线全流程指南!
  • COMSOL模拟锌离子电池锌负极电场模型教程:从零开始构建并详细解析源文件,适合初学者的电场建模教学
  • 5分钟掌握LIBERO:开启终身机器人学习的革命性平台
  • 毕业设计实战:基于SpringBoot+MySQL的家政服务平台设计与实现,从需求到测试全流程避坑指南!
  • Slim模板引擎终极指南:如何快速构建SEO友好的网页
  • Gleam语言深度解析:类型安全与跨平台编程的新范式
  • Zigpy:Python驱动的智能家居Zigbee通信解决方案
  • VScode创建AI环境
  • PySide6从0开始学习的笔记(一) 学前班
  • 祝贺C++40周年
  • 毕业设计实战:基于SpringBoot的校友管理系统设计与实现,社交+招聘功能避坑指南!
  • 解决Ubuntu/Linux/Gnome 打开文件慢,使用chrome打开文件更慢/卡死问题
  • 光伏电站并网后如何玩转虚拟同步机?储能如何优雅地削峰填谷?今天咱们用Simulink搭个实战模型,拆解光储联合系统中的三大核心技能
  • 50040_基于微信小程序的项目管理系统
  • python学习第6天
  • 互联网大厂Java求职者面试技术深度文章示例
  • Electron应用自动更新与跨平台部署实战指南
  • 3步极速部署PLabel:智能标注系统的实战指南
  • Capacitor跨平台开发终极指南:用Web技术构建原生应用