Java中的泛型——类型介绍与使用详解

1.什么是泛型

        泛型(Generics)是 Java 提供的一种特性,使得类、接口、方法可以操作各种类型的对象,而不必在编写时指定具体的类型。泛型允许我们在定义时使用类型参数,并在实际使用时为这些参数提供具体的类型。泛型的主要目的是提高代码的通用性类型安全性可重用性

泛型的基本概念:

  • 类型参数:泛型使用的占位符,比如 TEKV 等,表示数据类型,具体类型在使用时指定。
  • 编译期检查:泛型提供了编译期类型检查,避免了类型转换异常。

        通过泛型,你可以在编译期就发现类型错误,而不必等到运行时。例如,一个 List<String> 会确保该列表只包含字符串。

List<String> list = new ArrayList<>(); 
list.add("Hello"); 
// list.add(123); // 编译时会报错,因为类型不匹配

2.如何使用泛型

泛型的使用分为几类:泛型类、泛型方法、泛型接口等。

泛型类

使用泛型类可以使类在定义时不指定具体的类型,而在使用时传递实际的类型。

class Box<T> { private T value; public void set(T value) { this.value = value; 
} public T get() { return value; } 
}

示例:

Box<Integer> intBox = new Box<>();
intBox.set(123);
System.out.println("Integer: " + intBox.get());  // 输出:Integer: 123Box<String> strBox = new Box<>();
strBox.set("Hello Generics");
System.out.println("String: " + strBox.get());  // 输出:String: Hello Generics

泛型方法

泛型方法是在方法定义中使用类型参数,使得方法可以操作多种类型。

public static <T> void printArray(T[] array) {for (T element : array) {System.out.print(element + " ");}System.out.println();
}Integer[] intArray = {1, 2, 3, 4, 5};
String[] strArray = {"A", "B", "C"};printArray(intArray);  // 输出:1 2 3 4 5
printArray(strArray);  // 输出:A B C

3.编写泛型

        编写泛型类、泛型方法或泛型接口时,首先要确定所操作的类型是未知的,在编写代码时你可以定义类型参数并在使用时指定实际类型。

泛型类

class Pair<K, V> {private K key;private V value;public Pair(K key, V value) {this.key = key;this.value = value;}public K getKey() {return key;}public V getValue() {return value;}
}

使用:

Pair<String, Integer> pair = new Pair<>("Age", 30);
System.out.println("Key: " + pair.getKey() + ", Value: " + pair.getValue());

泛型方法

编写泛型方法时,类型参数需在返回类型前声明。

public static <T> T getFirst(T[] array) {if (array == null || array.length == 0) {return null;}return array[0];
}String[] names = {"Alice", "Bob", "Charlie"};
System.out.println(getFirst(names));  // 输出:Alice

泛型接口

泛型接口定义在接口中使用类型参数,并在实现类中指定具体类型。

interface Container<T> {void set(T value);T get();
}class ContainerImpl<T> implements Container<T> {private T value;@Overridepublic void set(T value) {this.value = value;}@Overridepublic T get() {return value;}
}

第 4 章:擦拭法

        Java 的泛型是通过类型擦除(Type Erasure)实现的。这意味着在编译时,所有泛型信息都会被移除,类型参数会被替换为其原始类型(通常是 Object 或具体的类型边界)。这使得泛型可以与非泛型代码互操作,并保持向后兼容性。

擦拭法的影响

  1. 类型信息在运行时丢失:由于类型擦除,运行时无法获取泛型的类型参数。

    List<String> list = new ArrayList<>(); 
    if (list instanceof ArrayList<String>) { 
    // 编译错误,无法检测泛型类型 
    }
  2. 无法创建泛型数组:因为类型擦除会移除具体的类型信息,不能创建泛型数组。

    List<Integer>[] listArray = new List<Integer>[10]; // 编译错误

5.通配符

        通配符 ? 是泛型中的一种特殊类型,用于表示未知的类型。通配符常用于增强代码的灵活性,尤其是在泛型集合中使用。

通配符的种类

  1. 无界通配符 ?:表示任意类型。

    List<?> list = new ArrayList<>();
  2. 有界通配符(上界)? extends T:表示 T 及其子类。

    List<? extends Number> list = new ArrayList<Integer>(); // Integer 是 Number 的子类
  3. 有界通配符(下界)? super T:表示 T 及其父类。

    List<? super Integer> list = new ArrayList<Number>(); // Number 是 Integer 的父类

示例:

public static void printNumbers(List<? extends Number> list) {for (Number num : list) {System.out.println(num);}
}List<Integer> intList = Arrays.asList(1, 2, 3);
List<Double> doubleList = Arrays.asList(1.1, 2.2, 3.3);printNumbers(intList);  // 输出整数
printNumbers(doubleList);  // 输出浮点数

6.泛型与反射

        由于泛型在编译时被擦除,运行时类型信息被丢失,反射与泛型的结合有一些特殊的考虑。虽然运行时无法获取具体的类型参数,但你仍然可以通过反射获取泛型类型的一些信息,比如通过 getGenericType()

示例:使用反射获取泛型类型

import java.lang.reflect.*;class GenericExample<T> {private T value;
}public class Main {public static void main(String[] args) throws Exception {Field field = GenericExample.class.getDeclaredField("value");Type type = field.getGenericType();System.out.println("Generic Type: " + type);}
}

泛型与反射的局限性

  • 由于类型擦除,无法在运行时获得泛型的实际类型参数。
  • 无法创建泛型的实例,因为运行时不具有类型参数的信息。

7.总结

        通过泛型,Java 实现了类型安全的通用编程机制。无论是在类、方法还是接口中,泛型都大大提高了代码的复用性和灵活性。通过类型擦除和通配符机制,Java 泛型可以兼容旧版本代码,但在使用反射时需要小心泛型信息的丢失。

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

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

相关文章

Springboot整合knife4j生成文档

前言 在开发过程中&#xff0c;接口文档是很重要的内容&#xff0c;用于前端对接口的联调&#xff0c;也用于给其他方使用。但是手写相对比较麻烦。 当然也有swagger之类的&#xff0c;但是界面没有那么友好。 官网&#xff1a; 整合步骤 整合依赖 需要根据版本进行&…

如何使用 pnpm 进行打补丁patch操作?推荐两个方法

前言 作为一个前端开发者&#xff0c;我们每天都在和各种各样的库和依赖打交道。node_modules 目录中存放着我们项目的各种依赖。我们有时需要对其中的一些依赖进行修改&#xff0c;比如修复某个 bug 或者增加某些自定义功能。这时候&#xff0c;给 node_modules 打补丁就显得…

为您的 WordPress 网站打造完美广告布局 A5广告单元格插件

一个为 WordPress 网站量身定制的强大工具,它将彻底改变您展示广告的方式 灵活多变的布局设计 A5 广告单元格插件的核心优势在于其无与伦比的灵活性。无论您是想要创建整齐的网格布局,还是希望打造独特的不规则设计,这款插件都能满足您的需求。 自定义网格数量&#xff1a;从 2…

androidStudio编译导致的同名.so文件冲突问题解决

files found with path lib/arm64-v8a/libserial_port.so from inputs: ...\build\intermediates\library_jni\debug\jni\arm64-v8a\libserial_port.so C:\Users\...\.gradle\caches\transforms-3\...\jni\arm64-v8a\XXX.so 解决方式如下&#xff1a; 1.将gradle缓存文件删…

TwinCAT3安装 Advanced Motion Pack库

文章目录 一.简介二.安装方式1. 下载地址2. 双击下载好的安装包3. 选择语言&#xff08;只有英文和德语&#xff09;4. 点击Next5. 选择Accept6. 填写公司和组织名称&#xff08;随意&#xff09;7. 点击Install8. 等待安装完成9. 点击Finish 一.简介 TF5420 TC3 Motion Pick-…

深度学习-1:逻辑回归和梯度下降

逻辑回归 逻辑回归是一个二分分类问题 比如判断一张图片中是否是猫就是一个二类分类问题 图像由像素值组成&#xff0c;要将图像输入模型&#xff0c;就将其变为一个向量&#xff0c;该向量存储三个通道上的所有像素值&#xff0c;若图像尺寸为64x64x3&#xff0c;则向量维度…

RequestBody接收参数报错com.fasterxml.jackson.databind.exc.MismatchedInputException

目录&#xff1a; 1、错误现象2、解决办法3、最终验证 1、错误现象 报错的现象和代码如下&#xff1a; 2、解决办法 查了很多都说参数类型对不上&#xff0c;但是明明是对上的&#xff0c;没有问题&#xff0c;最后只有换接收方式后验证是可以的&#xff1b;最终想了一下&…

Unity3D 观察者模式

Unity3D 泛型事件系统 观察者模式 观察者模式是一种行为设计模式&#xff0c;通过订阅机制&#xff0c;可以让对象触发事件时&#xff0c;通知多个其他对象。 在游戏逻辑中&#xff0c;UI 界面通常会监听一些事件&#xff0c;当数据层发生变化时&#xff0c;通过触发事件&am…

网络参考模型总结

物理层&#xff1a; 电信号&#xff0c;有中继器、集线器等设备。 数据链路层&#xff1a;帧&#xff0c;有网桥、交换机等设备&#xff0c;通过mac地址。 网络层&#xff1a;包&#xff0c;有路由器等设备&#xff0c;通过IP地址。 传输层&#xff1a;段&#xff0c;有网…

rootless模式下istio ambient的流量管理测试

接上一篇rootless模式下istio ambient鉴权策略&#xff0c;本次测试管理流量的功能。 服务流量分割 Bookinfo应用程序有三个版本的reviews服务&#xff0c;接下来对这些版本进行分配流量控制测试。 longtdsubuntu:~$ kubectl get pod |grep reviews reviews-v1-746f96c9d4-2…

出类拔萃的四款录屏工具你pick哪一个?

在这个屏幕时代&#xff0c;录屏已经成为我们日常工作和娱乐中不可或缺的一部分。无论是为了记录游戏精彩瞬间&#xff0c;还是为了分享教程和经验&#xff0c;一个好的录屏工具都是必不可少的。今天&#xff0c;就让我为大家推荐几款电脑免费录屏工具&#xff0c;并分享一下使…

DDD通用语言、多尿和尿频-《分析模式》漫谈41

“Analysis Patterns”的第3章有这么一句&#xff1a; A patient with observations of the presence of thirst, weight loss, and polyuria indicates diabetes. 2004&#xff08;机械工业出版社&#xff09;中译本的译文为&#xff1a; 虽然没有完全使用类图&#xff08;类…

【C++_string类练习】仅仅反转字母

题目链接&#xff1a;仅仅反转字母 解题思路&#xff1a; 这种反转字符的题目我第一个想到的方法就是&#xff1a;双指针 一个指针在前start&#xff0c;一个指针在后back&#xff0c; 如果指针所指向的位置的值是字母&#xff0c;那么两个指针位置的值就进行交换&#xff0…

矿山企业电能智能化管理怎么实现

0引言 电力工业是国民经济和社会发展的基础&#xff0c;随着高质量发展要求的提升&#xff0c;提高能源效率对工业企业至关重要。有效提高电力能效的方法包括技术创新、监测用能行为和探索技术解决方案。智能化的电能管理是应对资源和环境压力的关键措施&#xff0c;对提高用电…

点餐小程序实战教程20广告管理

目录 1 创建数据源2 添加轮播容器3 创建变量4 绑定变量5 预览应用总结 一般餐厅需要有一些宣传&#xff0c;在我们的点餐页面可以在顶部加载广告位。广告主要是用轮播图的形式进行展示&#xff0c;本节我们介绍一下如果显示广告。 1 创建数据源 打开控制台&#xff0c;点击应用…

10-Docker安装Redis

10-Docker安装Redis Docker安装Redis 以 Redis 6.0.8 为例&#xff1a; docker pull redis:6.0.8直接pull会出现以下错误 [rootdocker ~]# docker pull redis:6.0.8 Error response from daemon: Get "https://registry-1.docker.io/v2/": net/http: request can…

【Cadence27】HDL拷贝工程➕Allegro导出DXF和3D文件STP

【转载】Cadence Design Entry HDL 使用教程 【Cadence01】Cadence PCB Edit相对延迟与绝对延迟的显示问题 【Cadence02】Allegro引脚焊盘Pin设置为透明 【Cadence03】cadence不小心删掉钢网层怎么办&#xff1f; 【Cadence04】一般情况下Allegro PCB设计时的约束规则设置&a…

卸载 Git

目录 打开 Geek找到 Git右键卸载 Git卸载完成等待扫描注册表点击完成清除Git在本地的配置文件 打开 Geek 找到 Git 右键卸载 Git 卸载完成 等待扫描注册表 点击完成 已经删除完毕 清除Git在本地的配置文件 进入 C:\Users\用户名 删除框起来的配置文件 &#x1f447; 源码资料…

webpack自定义插件 ChangeScriptSrcPlugin

插件文件 class ChangeScriptSrcPlugin {apply(compiler) {const pluginName "ChangeScriptSrcPlugin";compiler.hooks.compilation.tap(pluginName, (compilation, callback) > {compilation.hooks.htmlWebpackPluginAlterAssetTags.tapAsync(pluginName,(html…

DES对称加密算法

DES&#xff08;Data Encryption Standard&#xff0c;数据加密标准&#xff09;是一种对称加密算法。 算法概述 加密类型&#xff1a;对称加密&#xff08;同一密钥用于加密和解密&#xff09;。密钥长度&#xff1a;64位&#xff08;8字节&#xff09;&#xff0c;其中有效…