Java 泛型详解:全面掌握类型安全与灵活性的利器

Java 泛型详解:全面掌握类型安全与灵活性的利器

Java 泛型是自 Java 5 引入的一项关键特性,旨在提升代码的类型安全性和可复用性。泛型通过引入参数化类型,允许类、接口和方法操作具体类型的数据,而无需在定义时指定具体类型。本文将深入探讨 Java 泛型的基本概念、类型参数与界定、通配符的使用、泛型的限制与继承、类型擦除、桥方法、泛型数组的创建、反射中的泛型处理,以及泛型的高级用法。通过全面了解和掌握这些知识点,开发者可以编写出更加通用、灵活和安全的 Java 代码。

1. 泛型的基本概念

1.1 泛型类

泛型类允许在类定义中使用参数化类型。这意味着类可以操作某种特定类型的数据,而在实例化类时才指定这种类型。

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

使用泛型类时,具体的类型参数在实例化时确定:

Box<Integer> integerBox = new Box<>();
integerBox.set(10);
Integer value = integerBox.get();
1.2 泛型接口

类似于泛型类,泛型接口允许在接口定义中使用参数化类型。

public interface Container<T> {void add(T item);T get(int index);
}

实现泛型接口:

public class Box<T> implements Container<T> {private List<T> items = new ArrayList<>();@Overridepublic void add(T item) {items.add(item);}@Overridepublic T get(int index) {return items.get(index);}
}
1.3 泛型方法

泛型方法使得方法可以独立于类而操作某种特定类型的数据。泛型方法的类型参数放在方法的返回类型之前。

public class Util {public static <T> void printArray(T[] inputArray) {for (T element : inputArray) {System.out.printf("%s ", element);}System.out.println();}
}

调用泛型方法:

Integer[] intArray = {1, 2, 3, 4, 5};
Util.printArray(intArray);

2. 类型参数和类型参数界定

2.1 类型参数

类型参数是泛型中的占位符,通常用单个大写字母表示:

  • E:元素(Element)
  • K:键(Key)
  • V:值(Value)
  • N:数字(Number)
  • T:类型(Type)
2.2 类型参数的界定

类型参数可以被限定,使得它只能是某个类或接口的子类或实现类。

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

这样,Box 类的实例只能接受 Number 类型及其子类作为类型参数。

多重界定
类型参数可以有多个边界,使用 & 符号进行分隔。

public class Box<T extends Number & Comparable<T>> {private T t;public void set(T t) {this.t = t;}public T get() {return t;}
}

3. 通配符

通配符用于泛型中的未知类型。

3.1 无界通配符

无界通配符 <?> 表示未知类型,通常用于只读访问的场景。

public void printList(List<?> list) {for (Object element : list) {System.out.println(element);}
}

调用方法:

List<String> stringList = Arrays.asList("one", "two", "three");
printList(stringList);
3.2 上界通配符

上界通配符 <? extends T> 表示类型是 T 或 T 的子类,通常用于读取的场景。

public void process(List<? extends Number> list) {for (Number number : list) {System.out.println(number.doubleValue());}
}

调用方法:

List<Integer> integerList = Arrays.asList(1, 2, 3);
process(integerList);
3.3 下界通配符

下界通配符 <? super T> 表示类型是 T 或 T 的超类,通常用于写入的场景。

public void addNumbers(List<? super Integer> list) {list.add(1);list.add(2);
}

调用方法:

List<Number> numberList = new ArrayList<>();
addNumbers(numberList);

4. 泛型的限制

  • 不能使用基本类型作为类型参数,例如 Box 是非法的,必须使用包装类 Box。
  • 静态成员中不能使用类型参数,因为类型参数是在实例化时确定的,而静态成员与实例无关。
  • 实例创建时不能使用类型参数,例如 new T() 是非法的,因为类型参数在运行时被擦除。
  • 泛型数组不能直接创建,例如 new T[10] 是非法的。可以通过创建 Object 数组并进行类型转换来间接实现:
T[] array = (T[]) new Object[10];

5. 泛型与继承

泛型支持继承,但需要注意类型兼容性。

class Parent<T> { }
class Child<T> extends Parent<T> { }Parent<String> parent = new Parent<>();
Child<String> child = new Child<>();

但是,不能将 Parent 赋值给 Parent,因为泛型是不协变的。

泛型的协变和逆变
虽然泛型类型参数是不协变的,但是可以使用通配符来实现协变和逆变:

List<? extends Number> covariantList = new ArrayList<Integer>(); // 协变
List<? super Integer> contravariantList = new ArrayList<Number>(); // 逆变

6. 类型擦除

Java 的泛型在编译时会进行类型擦除,以保证与旧版本的 Java 兼容。类型擦除后,所有泛型信息都会被移除,替换为其限定的类型或 Object。

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

类型擦除后相当于:

public class Box {private Object t;public void set(Object t) { this.t = t; }public Object get() { return t; }
}

7. 桥方法

在类型擦除过程中,为了保证类型安全,编译器会生成桥方法。例如:

class Parent<T> {public T method(T t) { return t; }
}class Child extends Parent<String> {public String method(String t) { return t; }
}

生成桥方法后:

class Child extends Parent<String> {public String method(String t) { return t; }public Object method(Object t) { return method((String) t); } // 桥方法
}

8. 泛型数组

由于类型擦除的限制,Java 不支持直接创建泛型数组。可以通过创建 Object 数组并进行类型转换来间接实现:

T[] array = (T[]) new Object[10];

9. 泛型的使用场景

泛型被广泛应用于 Java 的集合框架、定义自定义泛型类和方法、类型参数界定等场景。

  • 集合框架:如 List、Set、Map<K, V> 等。
  • 自定义泛型类和方法:提高代码的复用性和类型安全。
  • 类型参数界定:如 Comparable 接口。

10. 泛型与反射

在使用反射时,泛型类型会被擦除为原始类型,无法直接获取泛型类型的信息。但可以通过反射获取泛型的实际类型参数。

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;public class GenericTypeDemo<T> {public static void main(String[] args) {GenericTypeDemo<String> demo = new GenericTypeDemo<>();Type type = demo.getClass().getGenericSuperclass();if (type instanceof ParameterizedType) {ParameterizedType parameterizedType = (ParameterizedType) type;Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();for (Type actualTypeArgument : actualTypeArguments) {System.out.println(actualTypeArgument);}}}
}

11. 泛型擦除后的副作用

类型擦除会导致一些潜在的问题,例如类型转换异常和类型安全问题。

public class Box<T> {private T t;public void set(T t) {this.t = t;}public T get() {return t;}public static void main(String[] args) {Box<String> stringBox = new Box<>();stringBox.set("Hello");Box rawBox = stringBox; // 允许的,但是会有类型安全问题rawBox.set(10); // 运行时异常:ClassCastException}
}

12. 泛型的高级用法

12.1 泛型的嵌套

泛型类型可以嵌套使用,例如 Map<K, List>。

Map<String, List<Integer>> map = new HashMap<>();
12.2 类型推断

Java 7 引入了菱形操作符 <>,使得编译器可以推断泛型的类型参数,从而减少冗长的代码。

List<String> list = new ArrayList<>();
12.3 泛型的类型推导

Java 8 引入了更强大的类型推导机制,允许在方法调用中推导出类型参数。

public static <T> List<T> emptyList() {return new ArrayList<T>();
}List<String> list = emptyList();

13. 总结

Java 泛型极大地提高了代码的类型安全性和可复用性,使得代码更加通用和灵活。理解并掌握泛型的使用对于编写高质量的 Java 代码至关重要。通过深入了解泛型的各种特性和限制,可以更好地利用泛型来编写类型安全、灵活和高效的代码。

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

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

相关文章

rtsp python实现

1. rtsp rtp rtcp https://hope-wisdom.blog.csdn.net/article/details/138259027 2.rtsp加速 https://mp.weixin.qq.com/s/0C1b-8pFw0HaE1xpNbrxxw 3. 实现了一部分获取数据 import socket import base64 import threading import struct# 定义 RTSP 请求 def send_rtsp_…

目标检测基础初步学习

目标检测&#xff08;Object Detection&#xff09; 目标检测任务说明 在动手学习深度学习中对目标检测任务有如下的描述。 图像分类任务中&#xff0c;我们假设图像中只有一个主要物体对象&#xff0c;我们只关注如何识别其类别。 然而&#xff0c;很多时候图像里有多个我们…

【C++软件调试技术】什么是pdb文件?如何使用pdb文件?哪些工具需要使用pdb文件?

目录 1、什么是pdb文件&#xff1f; 2、如何配置生成pdb文件&#xff1f; 3、pdb文件的时间戳和文件名称 3.1、pdb文件的时间戳 3.2、pdb文件的文件名称 4、有pdb文件才能在Visual Studio中调试代码 5、在Windbg中使用pdb文件 5.1、使用lm命令查看二进制文件的时间戳&a…

翻译《The Old New Thing》- Why do atoms start at 0xC000?

Why do atoms start at 0xC000? - The Old New Thing (microsoft.com)https://devblogs.microsoft.com/oldnewthing/20080429-00/?p22543 Raymond Chen 2008年04月03日 有两种类型的原子&#xff0c;即所谓的整数原子&#xff0c;它们只是一些小整数&#xff0c;还有就是没有…

GE的六西格玛是怎么成功的?

六西格玛作为一种先进的质量管理方法&#xff0c;旨在通过消除缺陷、提高流程效率来降低成本、增强客户满意度。GE作为最早采用六西格玛的公司之一&#xff0c;其成功的原因首先离不开高层领导对精益六西格玛理念的坚定支持和推动。公司高层不仅亲自参与培训和项目实践&#xf…

何为云防护?有何作用

云防护又称云防御。随着Internet互联网络带宽的增加和多种DDOS 黑客工具的不断发布&#xff0c;云计算越演越热&#xff0c;DDOS拒绝服务攻击的实施越来越容易&#xff0c;DDOS攻击事件正在成上升趋势。出于商业竞争、打击报复和网络敲诈等多种因素&#xff0c;导致很多IDC 托管…

Python assertTrue用法:深入探索与实用技巧

Python assertTrue用法&#xff1a;深入探索与实用技巧 在Python的单元测试框架中&#xff0c;assertTrue是一个核心断言方法&#xff0c;用于验证某个条件是否为真。本文将深入探讨assertTrue的用法&#xff0c;并从四个方面、五个方面、六个方面和七个方面对其进行详细解析&…

一分钟了解香港的场外期权报价

香港的场外期权报价 在香港这个国际金融中心&#xff0c;场外期权交易是金融市场不可或缺的一部分。场外期权&#xff0c;作为一种非标准化的金融衍生品&#xff0c;为投资者提供了在特定时间以约定价格买入或卖出某种资产的机会。对于希望参与这一市场的投资者来说&#xff0…

电脑记事本怎么恢复之前的内容记录

每个人都曾有过这样的时刻——在记事本上精心记录下的重要内容&#xff0c;一不小心就被删除了。那种心情&#xff0c;仿佛一瞬间从山顶跌落到谷底&#xff0c;无尽的懊悔涌上心头。我也曾遭遇过这样的困境&#xff0c;那些消失的文字对我来说意义非凡&#xff0c;它们的丢失仿…

基于小波变换贝叶斯LMMSE估计的图像降噪方法(MATLAB 2018)

自从小波被发现以来&#xff0c;由于其优良的时频局部化性能&#xff0c;大大解决了信号与图像降噪的难题。利用小波降噪大致有三种方法&#xff0c;分别是基于小波模极大值原理、基于小波变换系数的相关性&#xff0c;和最为常用的小波阈值函数法。 基于小波模极大值降噪 该…

AI程序员来了,大批码农要失业

根据GitHub发布的《Octoverse 2021年度报告》&#xff0c;2021年中国有755万程序员&#xff0c;排名全球第二。 ChatGPT的出现&#xff0c;堪比在全球互联网行业点燃了一枚“核弹”&#xff0c;很多人都会担心“自己的工作会不会被AI取代”。 而2024年的AI进展速度如火箭般&am…

S4 BP 维护

前台输入Tcode:BP 问候填写金税开票信息使用的开户行名称,注释填写金税开票信息使用的开户行代码 屏幕下滑按需填写其他数据,如:街道2,街道3,街道/门牌号,街道4,街道5,区域,邮编、城市、国家、地区、语言,电话(发票地址里的电话(必须是客户开票资料里提供的电话,会…

【MyBatisPlus】MyBatisPlus条件查询

【MyBatisPlus】MyBatisPlus条件查询 文章目录 【MyBatisPlus】MyBatisPlus条件查询1、查询条件方式2、组合条件3、NULL值处理4、查询投影-设置【查询字段、分组】5、查询条件6、字段映射与表名映射问题导入 1、查询条件方式 MyBatisPlus将书写复杂的SQL查询条件进行了封装&…

JSON 数据格式化方法

文章目录 数据介绍IDE 或脚本格式化在线工具网址总结 数据介绍 JSON&#xff08;JavaScript Object Notation&#xff09;是一种轻量级的数据交换格式&#xff0c;它基于JavaScript 编程语言的一个子集。尽管它起源于 JavaScript&#xff0c;但 JSON 已经成为了一个完全独立于…

保护隐私下的数据提取:方法与伦理考量

在数字化时代&#xff0c;数据的收集和分析为我们提供了前所未有的机会和便利。然而&#xff0c;这些机遇也伴随着隐私泄露的严重风险。如何在保护个人隐私的前提下进行数据提取&#xff0c;已成为一个亟待解决的问题。本文将探讨保护隐私下的数据提取方法&#xff0c;并深入分…

2024专精特新趋势论坛,汉王友基分享数字化创新实践之路

5月31日&#xff0c;由深圳市中小企业服务局作为指导单位&#xff0c;36氪主办的“WISE新风向2024专精特新趋势论坛”在粤港澳大湾区顺利举办。 汉王友基作为国家级专精特新“小巨人”企业代表&#xff0c;受邀参加此次大会&#xff0c;企业CTO邓立明先生进行了《数字赋能&…

让企业自己掌握数据主权,可道云teamOS让企业数据私有化不再是难题,让企业数据更安全、更可控

越来越多的企业开始意识到&#xff0c;仅仅依赖公共云存储服务可能无法满足其对于数据安全性的高标准要求。 毕竟每年都会有不同程度的数据泄露问题爆出&#xff0c;导致大家在使用企业网盘的时候也总是惴惴不安。一旦数据泄露或被非法获取&#xff0c;企业将面临巨大的经济损…

geotrust泛域名https600元

泛域名https证书&#xff0c;也可以称之为通配符https证书&#xff0c;是开发者用来保障网站安全、提升用户信任度的方案之一。开发者可以使用泛域名https证书为多个网站进行数据加密以及身份认证服务&#xff0c;提升网站的安全性。今天就随SSL盾小编了解geotrust旗下的泛域名…

如何理解 Java 线程的概念及线程的创建和管理,包括 Runnable 接口和 Thread 类

多线程编程是现代软件开发中的重要技术&#xff0c;能够显著提高程序的效率和响应速度。Java 提供了丰富的多线程编程支持&#xff0c;使开发者可以轻松地创建和管理线程。 1. 线程的基本概念 1.1 进程与线程 进程&#xff1a;是操作系统中独立运行的程序&#xff0c;每个进…

AI大模型页面

自己做的AI&#xff0c;模仿GPT。 访问地址&#xff1a;欢迎 请大家给点意见&#xff0c;需要追加哪些功能。