JavaSE—泛型

1 泛型定义和基本使用

泛型是JDK1.5以后才有的, 可以在编译时期进行类型检查,且可以避免频繁类型转化!

@Test
public void test1() {List list = new ArrayList();list.add("ZhangSan");list.add(1);//集合使用 取出元素Object object = list.get(0);System.out.println(object);String str1 = (String) list.get(0);System.out.println(str1);//String str2 = (String) list.get(1);//ClassCastException
}//使用泛型
@Test
public void test2() {//声明泛型集合的时候指定元素的类型List<String> list = new ArrayList<>();list.add("Java");//泛型解决的的是编译时期的报错,提前检查//list.add(1);//会报错String str = list.get(0);System.out.println(str);
}
    @Testpublic void test3() {// 两端的数据类型必须要一致List<Object> list1 = new ArrayList<Object>();List<String> list2 = new ArrayList<String>();// 右侧的泛型可以不写List<String> list3 = new ArrayList<>();// 只在右侧写泛型不起作用List list4 = new ArrayList<String>();list4.add(1);// 两边不一致编译时候报错 -----> 红色波浪线// List<Object> list5 = new ArrayList<String>();// 泛型类型必须为引用数据类型// List<int> list6 = new ArrayList<>();}

2 泛型擦除

泛型只在编译时期有效,编译后的字节码文件中不存在有泛型信息!

  1. 帮助开发者写出正确的代码。

  2. 虚拟机的向下兼容问题

    @Testpublic void test5() {List<String> list1 = new ArrayList<>();List<Integer> list2 = new ArrayList<>();Class clazz1 = list1.getClass();Class clazz2 = list2.getClass();System.out.println(clazz1 == clazz2);System.out.println(clazz1);System.out.println(clazz2);}//泛型擦除:参数都是List list   认为是同一个方法/*public void add(List<Student> list) {}public void add(List<Teacher> list) {}*///'add(List<Student>)' clashes with 'add(List<Teacher>)'; both methods have same erasure

在这里插入图片描述

3 泛型方法/泛型类/泛型接口

作用:设计公用的类、方法,对公用的业务实现进行抽取!使程序更灵活!

泛型方法

public class GenericDemo2 {public Student add1(Student student, Teacher teacher) {return null;}public <K,T> K add(K k, T t) {return k;}@Testpublic void test1() {// 使用泛型方法:  在使用泛型方法的时候,确定泛型类型Float result1 = add(1.0f, 1);System.out.println(result1);String result2 = add("abc", 1);System.out.println(result2);}
}

泛型类

不用像泛型方法那样每个方法都要声明。

public class BaseDao<T> {public <K> K save(K k) {return k;}public void add(T t) {}public void update(T t) {}
}@Test
public void test2() {Student student = new Student();BaseDao<Student> baseDao1 = new BaseDao<>();baseDao1.add(student);baseDao1.update(student);Teacher teacher = new Teacher();BaseDao<Teacher> baseDao2 = new BaseDao<>();baseDao2.add(teacher);baseDao2.update(teacher);
}

泛型接口

public interface IBaseDao<T> {void add(T t );void update(T t );
}
//泛型接口类型确定: 在业务实现类中直接确定接口的类型
public class PersonDao implements IBaseDao<Person> {
}

4 泛型关键字

常用的 ?, T, E, K, V, N的含义

我们在泛型中使用通配符经常看到T、F、U、E,K,V其实这些并没有啥区别,我们可以选 A-Z 之间的任何一个字母都可以,并不会影响程序的正常运行。

只不过大家心照不宣的在命名上有些约定:

T (Type) 具体的Java类

E (Element)在集合中使用,因为集合中存放的是元素

K V (key value) 分别代表java键值中的Key Value

N (Number)数值类型

? 表示不确定的 Java 类型

泛型中:

? 在泛型代码中,问号(?)称为通配符,用来表示不确定的 Java 类型

extends 元素的类型必须继承自指定的类

super 元素的类型必须是指定的类的父类

使用<?>通配符,可以使方法更加灵活,可以接受不同类型的 List 列表,同时又不会对List进行修改,保证代码的安全性。

既要限定传递过来的是集合类型,但是又不确定里面类型List<?> list

public void add1(List<?> list) {}// extends      元素的类型必须继承自指定的类
/**
* list集合只能处理 Double/Float/Integer等类型
* 限定元素范围:元素的类型要继承自Number类  (上限)
* @param list
*/
public void add2(List<? extends Number> list) {
}@Test
public void testGeneric23() throws Exception {List<Double> list1 = new ArrayList<Double>();List<Float> list2 = new ArrayList<Float>();List<Integer> list3 = new ArrayList<Integer>();List<String> list4 = new ArrayList<String>();// 调用add2(list1);add2(list2);add2(list3);//add2(list4);
}/**
* super限定元素范围:必须是String父类,String类也可以   (下限)
* @param list
*/
public void add3(List<? super String> list) {
}@Test
public void testGeneric24() throws Exception {// 调用上面方法,必须传入String的父类List<Object> list1 = new ArrayList<Object>();List<String> list2 = new ArrayList<String>();List<Integer> list3 = new ArrayList<Integer>();//add(list3);
}

5 List和List<?>的区别

ChatGPT 也可能会犯错。请核查重要信息。

这两段代码之间的主要区别在于泛型的使用。让我们仔细看看每段代码,并解释它们的差异。

第一段代码

public void add(List<?> list) {//list.add(1);//Required type: capture of ? | Provided:intfor (Object object : list) {System.out.println(object);}
}
解释
  • List<?>:这是一个使用通配符 ? 的泛型列表。这表示列表可以包含任何类型的元素,但是我们不能向这个列表添加任何元素(除了 null)。
    • 为什么不能添加元素:由于 List<?> 表示一个未知类型的列表,编译器无法确定添加的元素是否与列表的实际类型兼容。因此,添加操作会导致编译错误。
    • 遍历元素:我们可以遍历这个列表,并将每个元素作为 Object 类型处理,因为我们不知道确切的元素类型。
示例:
public void add(List<?> list) {// 编译错误:不能向未知类型的列表添加元素// list.add(1);// 可以遍历列表并打印元素for (Object object : list) {System.out.println(object);}
}

第二段代码

public void add1(List list) {//list.add(1);//Required type: capture of ? | Provided:intfor (Object object : list) {System.out.println(object);}
}
解释
  • List(原始类型):这是一个原始类型的列表,没有使用泛型。这意味着列表可以包含任何类型的元素,且类型检查在编译时被绕过,但在运行时可能导致 ClassCastException
    • 可以添加元素:尽管没有泛型限制,可以向列表添加元素。然而,这种做法会失去类型安全性。
    • 遍历元素:我们可以遍历这个列表,并将每个元素作为 Object 类型处理。
示例:
public void add1(List list) {// 可以向原始类型的列表添加元素,但这不安全list.add(1);// 可以遍历列表并打印元素for (Object object : list) {System.out.println(object);}
}

关键区别

  1. 类型安全性

    • List<?> 提供类型安全性,不能向列表添加元素,除了 null
    • List 是原始类型,没有类型安全性,可以向列表添加任何类型的元素,但这可能会在运行时导致 ClassCastException
  2. 编译检查

    • List<?> 在编译时会进行类型检查,确保没有非法的添加操作。
    • List 由于没有泛型,编译器无法提供类型检查,这可能导致潜在的运行时错误。
  3. 可添加元素

    • List<?> 中,不能添加元素(除了 null)。
    • List 中,可以添加任何类型的元素。

总结

  • List<?>:使用通配符泛型表示未知类型的列表,提供类型安全性,但不能添加元素。
  • List:使用原始类型,没有类型安全性,可以添加任何类型的元素,但可能导致运行时错误。

选择使用哪种类型取决于具体的需求和安全性考虑。对于大多数情况下,使用泛型是推荐的做法,因为它提供了编译时的类型检查,从而提高了代码的安全性和可维护性。

6 全面简单地介绍下Java的泛型及其作用

ChatGPT 也可能会犯错。请核查重要信息。

Java的泛型

泛型是Java编程语言的一项强大特性,它允许你定义和使用带有类型参数的类、接口和方法。泛型提供了编译时的类型检查和代码重用性,减少了类型转换的需要和运行时错误的风险。

主要特性和语法

  1. 泛型类和接口
    定义包含类型参数的类或接口。

    public class Box<T> {private T content;public void setContent(T content) {this.content = content;}public T getContent() {return content;}
    }
    
  2. 泛型方法
    定义带有类型参数的方法。

    public class Util {public static <T> void printArray(T[] array) {for (T element : array) {System.out.println(element);}}
    }
    
  3. 类型推断
    在调用泛型方法时,编译器可以根据传递的参数推断出类型参数。

    Box<Integer> intBox = new Box<>();
    intBox.setContent(123);
    Integer content = intBox.getContent();
    
  4. 通配符
    使用问号 ? 表示未知类型。

    public void processList(List<?> list) {for (Object obj : list) {System.out.println(obj);}
    }
    
  5. 边界通配符
    限制类型参数的范围,可以是上界或下界。

    public void processNumbers(List<? extends Number> list) { // 上界通配符for (Number num : list) {System.out.println(num);}
    }public void addNumbers(List<? super Integer> list) { // 下界通配符list.add(123);
    }
    
  6. 泛型限制
    泛型类型不能是基本类型(如 intchar 等),只能是引用类型(如 IntegerString 等)。

    // 正确的写法
    List<Integer> list = new ArrayList<>();// 错误的写法
    // List<int> list = new ArrayList<>();
    

泛型的作用

  1. 类型安全
    泛型提供了编译时的类型检查,防止类型转换错误。例如,使用泛型集合可以确保集合中的所有元素都是指定类型。

    List<String> list = new ArrayList<>();
    list.add("hello");
    // list.add(123); // 编译时错误
    
  2. 减少类型转换
    使用泛型可以减少显式类型转换的需要,从而使代码更加简洁和可读。

    List<String> list = new ArrayList<>();
    list.add("hello");
    String str = list.get(0); // 不需要类型转换
    
  3. 代码重用
    泛型使得可以编写通用的类、接口和方法,这些代码可以与不同类型的对象一起工作,提高代码的重用性。

    public class Pair<T, U> {private T first;private U second;public Pair(T first, U second) {this.first = first;this.second = second;}// getter 和 setter
    }Pair<String, Integer> pair = new Pair<>("age", 30);
    
  4. 提高代码可读性
    泛型使得代码更加清晰和可读,因为类型信息明确。

    // 不使用泛型
    List list = new ArrayList();
    list.add("hello");
    String str = (String) list.get(0); // 类型转换// 使用泛型
    List<String> list = new ArrayList<>();
    list.add("hello");
    String str = list.get(0); // 无需类型转换
    

总结

Java 的泛型是一种用于定义和使用带有类型参数的类、接口和方法的强大特性。它提供了类型安全、减少类型转换、代码重用和提高代码可读性等诸多优点。在现代 Java 编程中,泛型广泛应用于集合框架和许多库中,极大地增强了语言的灵活性和安全性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/23779.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

R语言数据探索和分析22-使用随机森林和聚类算法探索和预测健康状况

一、研究背景 在两个实验中&#xff0c;使用了一组综合性的生物统计数据来探索和预测健康状况&#xff08;特别是疾病的发生&#xff09;。实验的核心在于应用高级数据分析技术&#xff0c;具体包括随机森林分类和聚类分析&#xff0c;来洞察和预测个体的健康状况。首先&#…

【十大排序算法】选择排序

选择就像是在谱曲&#xff0c;每个决定就是一个音符&#xff0c;只有将它们有序地安排在一起&#xff0c;才能奏响美妙的乐章。 文章目录 一、选择排序的思想二、选择排序的发展历程三、选择排序具象化四、选择排序算法实现五、选择排序的特性推荐阅读 一、选择排序的思想 选…

详解大厂实时数仓建设V4.0

一、实时数仓建设背景 1. 实时需求日趋迫切 目前各大公司的产品需求和内部决策对于数据实时性的要求越来越迫切&#xff0c;需要实时数仓的能力来赋能。传统离线数仓的数据时效性是 T1&#xff0c;调度频率以天为单位&#xff0c;无法支撑实时场景的数据需求。即使能将调度频…

参数传递和剪枝,从修剪二叉树谈起

669. 修剪二叉搜索树 - 力扣&#xff08;LeetCode&#xff09; 一、参数传递 Java中的参数传递方式只有一种&#xff0c;那就是值传递。如果我们传的是基本数据类型&#xff0c;那么函数接收到的就是该数据的副本&#xff0c;如果我们传的是对象&#xff0c;那么函数接收到的就…

【Qt知识】部分QWidget属性表格

QWidget是Qt库中所有图形用户界面组件的基类&#xff0c;它提供了大量属性以供自定义和配置控件的行为和外观。下面列出了一些主要的QWidget属性及其作用。 属性 作用 accessibleName 控件的辅助技术名称&#xff0c;用于无障碍访问。 accessibleDescription 控件的辅助技…

CSS真题合集(一)

CSS真题合集&#xff08;一&#xff09; 1. 盒子模型1.1 盒子模型的基本组成1.2 盒子模型的实际大小1.3 盒子模型的两种类型1.4 设置盒子模型1.5 弹性盒子模型 2. BFC2.1 主要用途2.2 触发BFC的方法2.2 解决外边距的塌陷问题&#xff08;垂直塌陷&#xff09; 3. 响应式布局3.1…

接口自动化框架封装思想建立(全)

httprunner框架&#xff08;上&#xff09; 一、什么是Httprunner&#xff1f; 1.httprunner是一个面向http协议的通用测试框架&#xff0c;以前比较流行的是2.X版本。 2.他的思想是只需要维护yaml/json文件就可以实现接口自动化测试&#xff0c;性能测试&#xff0c;线上监…

spring aop小记

一、aop概念 面向切面编程 参考&#xff1a;https://blog.csdn.net/lhj520cb/article/details/125820513 常用术语解释&#xff08;根据代码理解的&#xff09;&#xff1a; Aspect(切面)&#xff1a;Advice 通知(即增强)和 Pointcut 切点的结合。&#xff08;数学上可以理…

【Android面试八股文】Java异常机制中,异常Exception与错误Error区别是什么?

Java异常机制中,异常Exception与错误Error区别是什么? 这道题想考察什么? 在开发时需要时候需要自定义异常时,应该选择定义Excption还是Error? 编写的代码触发Excption或者Error分别代表什么? 考察的知识点 Java异常机制 考生应该如何回答 在Java中存在一个 Throwa…

Git - 详解 创建一个新仓库 / 推送现有文件夹 / 推送现有的 Git 仓库 到私有Gitlab

文章目录 【推送现有文件夹】详细步骤指令说明Git 全局设置设置Git全局用户名设置Git全局电子邮件地址 推送现有文件夹1. 进入现有文件夹2. 初始化Git仓库并设置初始分支为main3. 添加远程仓库4. 添加所有文件到暂存区5. 提交更改6. 推送代码到远程仓库并设置上游分支 创建一个…

ESXi内安装OpenWrt

目录 0、前言 1、环境 2、转换格式 3、创建虚拟机 4、OpenWrt设置 5、单臂流量测试 6、总结 0、前言 前几天在ESXi中先安装了PVE,然后在PVE中安装OpenWrt,没有来得及深入测试,仅仅作为安装和熟悉PVE的过程。后来转念一想为什么不在ES…

CS1061 “HtmlHelper”未包含“Partial”的定义,并且找不到可接受第一个“HtmlHelper”类型参数的可访问扩展方法“Partial”

严重性 代码 说明 项目 文件 行 禁止显示状态 错误 CS1061 “HtmlHelper”未包含“Partial”的定义&#xff0c;并且找不到可接受第一个“HtmlHelper”类型参数的可访问扩展方法“Partial”(是否缺少 using 指令或程序集引用?) 14_Views_Message_E…

找嵌入式软件工作,freertos要掌握到什么程度?

对于嵌入式软件工程师来说&#xff0c;掌握RTOS&#xff08;实时操作系统&#xff09;的程度并不是决定性因素&#xff0c;而更重要的是工程思维和解决问题的能力。我这里有一套嵌入式入门教程&#xff0c;不仅包含了详细的视频讲解&#xff0c;项目实战。如果你渴望学习嵌入式…

Angular封装高德地图组件实现输入框搜索,地图点击选地点

Angular封装高德地图组件实现输入框搜索,地图点击选地点(Angular17版本) 话不多说直接上代码 创建一个独立组件 html代码: <div style"position: relative;"><input #searchInput nz-input placeholder"请输入地址"/><div #mapContaine…

力扣 48.旋转图像

题目描述&#xff1a; 给定一个 n n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。 你必须在 原地 旋转图像&#xff0c;这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,2,3],…

CLion配置

下载环境&#xff1a;MinGW-w64 - for 32 and 64 bit Windows - Browse Files at SourceForge.net 解压后找一个位置存放&#xff0c;一般放在和ide同一目录&#xff0c;方便查找 个人习惯配置调整&#xff1a; 项目创建 修改ide解码形式 项目右下角一般默认是utf8 文件编码改…

VS2019 QT无法打开 源 文件 “QTcpSocket“

VS2019 QT无法打开 源 文件 "QTcpSocket" QT5.15.2_msvc2019_64 严重性 代码 说明 项目 文件 行 禁止显示状态 错误(活动) E1696 无法打开 源 文件 "QTcpSocket" auto_pack_line_demo D:\vs_qt_project\auto_pack_line_de…

【区块链】truffle测试

配置区块链网络 启动Ganache软件 使用VScode打开项目的wordspace 配置对外访问的RPC接口为7545&#xff0c;配置项目的truffle-config.js实现与新建Workspace的连接。 创建项目 创建一个新的目录 mkdir MetaCoin cd MetaCoin下载metacoin盒子 truffle unbox metacoincontra…

如何减少Apache Spark日志的数量

修改log4j配置文件&#xff0c;没有就创建&#xff1a; 内容&#xff1a; # 设置日志记录器 log4j.rootCategoryWARN, console log4j.appender.consoleorg.apache.log4j.ConsoleAppender log4j.appender.console.targetSystem.err log4j.appender.console.layoutorg.apache.lo…

【栈】1096. 花括号展开 II

本文涉及知识点 栈 LeetCode 1096. 花括号展开 II 如果你熟悉 Shell 编程&#xff0c;那么一定了解过花括号展开&#xff0c;它可以用来生成任意字符串。 花括号展开的表达式可以看作一个由 花括号、逗号 和 小写英文字母 组成的字符串&#xff0c;定义下面几条语法规则&…