深入理解Java包装类与泛型的应用
今天我将带领大家进入Java包装类和泛型应用的学习。
我的个人主页
我的Java-数据结构专栏 :Java-数据结构,希望能帮助到大家。
一、Java包装类基础
二、Java泛型基础
三、Java包装类与泛型的结合
四、Java泛型进阶
五、Java包装类与泛型实战
一、Java包装类基础
在Java中,装箱(boxing)是指将基本数据类型(如int, char, double等)转换为对应的包装类对象(如Integer, Character, Double等)的过程。相反,拆箱(unboxing)是指将包装类对象转换回基本数据类型的过程。
从Java 5(JDK 1.5)开始,Java引入了自动装箱和拆箱机制,以简化基本数据类型和包装类之间的转换。这意味着在需要的时候,Java编译器会自动进行装箱和拆箱操作,而不需要程序员显式地调用转换方法。
- 包装类的定义与作用:包装类(Wrapper Classes)在Java编程语言中,指的是将基本数据类型(也称为原始数据类型,如int、char、double等)封装为对象的类。这些类使得基本数据类型可以作为对象进行处理,从而提供了更多的灵活性和功能。
-
Java中的包装类:在Java中,由于基本类型不是继承自Object,为了在泛型代码中可以支持基本类型,Java给每个基本类型都对应了 一个包装类型。
注意:除了 Integer 和 Character, 其余基本类型的包装类都是首字母大写。
自动装箱和拆箱示例代码
public class BoxingUnboxingExample {public static void main(String[] args) {// 自动装箱int primitiveInt = 10;Integer boxedInt = primitiveInt; // 编译器会自动调用 Integer.valueOf(int)// 自动拆箱int unboxedInt = boxedInt; // 编译器会自动调用 boxedInt.intValue()// 在算术运算中自动拆箱Integer anotherBoxedInt = 20;int result = boxedInt + anotherBoxedInt; // 实际上会拆箱为 int,然后执行加法运算,再装箱为 Integer(如果赋值给 Integer 变量)// 但由于 result 是 int 类型,所以这里只涉及拆箱,不涉及装箱// 显式装箱和拆箱(通常不需要这样做,因为自动装箱和拆箱已经足够)Integer explicitlyBoxedInt = Integer.valueOf(primitiveInt); // 显式装箱int explicitlyUnboxedInt = explicitlyBoxedInt.intValue(); // 显式拆箱// 打印结果以验证System.out.println("Primitive int: " + primitiveInt);System.out.println("Boxed int: " + boxedInt);System.out.println("Unboxed int: " + unboxedInt);System.out.println("Result of boxed int addition: " + result);System.out.println("Explicitly boxed int: " + explicitlyBoxedInt);System.out.println("Explicitly unboxed int: " + explicitlyUnboxedInt);}
}
-
性能考虑:虽然自动装箱和拆箱为程序员提供了便利,但在性能敏感的应用中,过多的装箱和拆箱操作可能会导致性能下降。因为装箱操作需要创建新的对象,而拆箱操作则涉及方法调用。
-
空指针异常:由于包装类对象是引用类型,因此它们可以是
null
。在进行拆箱操作时,如果包装类对象为null
,则会抛出NullPointerException
。例如,Integer nullInt = null; int value = nullInt;
这段代码会抛出空指针异常。 -
缓存机制:Java对某些包装类(如
Integer
、Boolean
、Byte
、Short
、Character
和Long
,但不适用于Float
和Double
)的值进行了缓存。对于Integer
来说,缓存范围是-128到127。在这个范围内的值被装箱时,会返回缓存中的对象,而不是创建新的对象。这有助于提高性能并减少内存使用。 -
比较操作:当比较两个包装类对象时,应该使用
equals()
方法而不是==
运算符,因为==
比较的是对象的引用而不是值。但是,对于缓存范围内的Integer
值,使用==
可能会得到正确的结果(因为它们是同一个对象的引用),但这是一种不可靠的做法,因为它依赖于Java的内部实现。 - 包装类的常用方法
- 转换方法(如valueOf, intValue等)
- 比较方法(如compareTo, equals等)
- 静态方法(如parseInt, parseDouble等)
二、Java泛型基础:
- 泛型的引入与意义
-
在Java 5之前,集合类(如ArrayList、HashMap等)只能存储Object类型的对象。这意 味着在存储和取出元素时,需要进行强制类型转换,这不仅繁琐,而且容易出现类型错误,如ClassCastException。为了解决这个问题,Java引入了泛型机制,允许在定义类、接口和方法时,使用类型参数来指代具体的类型,从而实现代码的通用性和类型安全性。
- 类型安全:
- 泛型可以在编译时期检查数据类型的合法性,避免出现类型不匹配导致的运行时错误。
- 编译器可以在编译期验证数据结构中的类型使用是否正确,降低运行时错误的概率。
- 代码复用:
- 泛型使得代码能够操作多种数据类型,而无需为每种类型单独实现一个版本。
- 一个泛型数据结构可适配多种类型,提高了代码的复用性。
- 代码清晰与简洁:
- 使用泛型可以使代码更加清晰、易懂,降低了代码阅读的难度。
- 避免了不必要的类型转换,减少了代码的冗余,提高了代码的可读性。
- 性能提升:
- 由于泛型避免了不必要的类型转换,所以在一定程度上可以提高程序的性能。
- 增强程序的健壮性:
- 通过在编译时期进行类型检查,泛型可以帮助开发者更早地发现并修复类型相关的错误,从而增强程序的健壮性。
- 泛型类:
- 在定义类时使用泛型参数,可以将具体的数据类型作为参数传递给类,并在类内部使用这些数据类型。
- 泛型方法:
- 在方法的返回值前使用泛型参数,可以将具体的数据类型作为参数传递给方法,并在方法内部使用这些数据类型。
- 泛型接口:
- 在定义接口时使用泛型参数,可以将具体的数据类型作为参数传递给接口,并在实现接口的类中使用这些数据类型。
-
Java泛型的引入极大地增强了代码的类型安全性和可读性,提高了代码的复用性和维护性。无论是标准库中的集合类,还是自定义的数据结构,都可以通过泛型实现更灵活、更高效的代码设计。在数据结构中,泛型为开发者提供了统一性和扩展性,同时也为程序的安全性和健壮性保驾护航。
-
泛型类是指在定义类时使用类型参数(也称为类型占位符)的类。类型参数在类名后面的尖括号<>
中指定。
// 定义一个泛型类 Box
public class Box<T> {// T 是类型参数,表示任意类型private T content;public void setContent(T content) {this.content = content;}public T getContent() {return content;}
}
使用泛型类时,可以指定具体的类型参数:
Box<Integer> integerBox = new Box<>();
integerBox.setContent(100);
Integer content = integerBox.getContent();
泛型接口与泛型类的定义类似,只是在接口名后使用尖括号指定类型参数。
// 定义一个泛型接口 Pair
public interface Pair<K, V> {K getKey();V getValue();
}
实现泛型接口时,需要指定具体的类型参数:
public class OrderedPair<K, V> implements Pair<K, V> {private K key;private V value;public OrderedPair(K key, V value) {this.key = key;this.value = value;}@Overridepublic K getKey() {return key;}@Overridepublic V getValue() {return value;}
}
泛型方法是指在方法定义时使用类型参数的方法。类型参数在方法返回类型前和方法名后的尖括号中指定。
// 定义一个泛型方法 printArray
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};
printArray(intArray); // 输出: 1 2 3 4 5
Java集合框架中的许多类都是泛型的,如ArrayList
、HashMap
等。使用泛型集合可以避免类型转换和潜在的ClassCastException
。
ArrayList<String> stringList = new ArrayList<>();
stringList.add("Hello");
stringList.add("World");for (String s : stringList) {System.out.println(s);
}
泛型通配符?
用于表示未知的类型。它主要有两种形式:无界通配符(?
)、上界通配符(? extends SomeType
)和下界通配符(? super SomeType
)。
// 使用无界通配符
List<?> unknownList = new ArrayList<String>();// 使用上界通配符
List<? extends Number> numberList = new ArrayList<Integer>();
// numberList 可以是 Integer、Double、Float 等 Number 子类的列表,但不能添加除 null 以外的元素// 使用下界通配符
List<? super Integer> integerSuperList = new ArrayList<Number>();
// integerSuperList 可以是 Number 或 Number 的父类(如 Object)的列表,可以添加 Integer 或 Integer 的子类对象
三、Java包装类与泛型的结合
包装类与泛型的结合:
当包装类与泛型结合使用时,可以创建更加灵活和类型安全的集合和数据结构。例如,ArrayList<Integer>
是一个使用Integer
包装类的泛型集合,它可以存储整数值,并且提供了类型安全的保证。
import java.util.ArrayList;
import java.util.List;public class WrapperGenericsExample {public static void main(String[] args) {// 创建一个存储Integer对象的ArrayListList<Integer> integerList = new ArrayList<>();// 向列表中添加整数(自动装箱)integerList.add(10);integerList.add(20);integerList.add(30);// 遍历列表并打印每个元素(自动拆箱)for (Integer integer : integerList) {System.out.println(integer);}// 使用包装类的方法int sum = 0;for (Integer integer : integerList) {sum += integer.intValue(); // 使用intValue()方法将Integer转换为int}System.out.println("Sum: " + sum);}
}
ArrayList<Integer>
是一个泛型集合,它使用Integer
包装类来存储整数。由于使用了泛型,我们得到了类型安全的保证:我们不能向integerList
中添加除Integer
对象以外的任何对象(除了null
,但在Java 5及更高版本中,泛型集合通常不允许存储null
以避免潜在的NullPointerException
)。
四、Java泛型进阶:
泛型擦除示例:
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;// 定义一个简单的泛型类
public class Box<T> {private T content;public void setContent(T content) {this.content = content;}public T getContent() {return content;}// 一个用于反射获取泛型类型信息的方法(注意:这个方法在泛型擦除后无法直接获取到T的具体类型)public Type getGenericType() {return ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];}public static void main(String[] args) {Box<String> stringBox = new Box<>();stringBox.setContent("Hello, World!");System.out.println(stringBox.getContent());// 通过反射尝试获取泛型类型信息(实际上在运行时已经擦除)Type genericType = stringBox.getGenericType();System.out.println("Generic type (at runtime, may be erased): " + genericType);// 但我们可以通过子类化并立即获取泛型信息来“绕过”擦除(这种方法不适用于所有情况)class StringBox extends Box<String> {}Type stringBoxType = StringBox.class.getGenericSuperclass().getActualTypeArguments()[0];System.out.println("Generic type of StringBox (inferred at compile time): " + stringBoxType);// 注意到,直接使用Box<String>的实例在运行时无法获取到T的具体类型,因为泛型信息已被擦除}
}
Java的类型推断机制允许编译器根据上下文自动推断出变量的类型,从而简化了代码的编写。以下是一个使用类型推断的示例:
import java.util.ArrayList;
import java.util.List;public class TypeInferenceExample {public static void main(String[] args) {// 在Java 7及更高版本中,可以在右侧的构造函数调用中省略泛型类型参数List<String> list1 = new ArrayList<>(); // 类型推断为List<String>// 在Java 10及更高版本中,可以使用var关键字进一步简化变量声明var list2 = new ArrayList<String>(); // 类型推断为ArrayList<String>(但var的使用应谨慎,以避免降低代码可读性)// 方法调用中的类型推断printList(list1); // 编译器可以推断出list1的类型为List<String>// 泛型方法调用中的类型推断List<Integer> numbers = createListWithNumbers(1, 2, 3, 4, 5); // 编译器可以推断出返回类型为List<Integer>}// 一个简单的泛型方法,用于创建并返回一个包含指定元素的列表public static <T> List<T> createListWithElements(T... elements) {List<T> list = new ArrayList<>();for (T element : elements) {list.add(element);}return list;}// 一个用于打印列表内容的方法(注意:这里不是泛型方法,只是接受泛型类型的参数)public static void printList(List<?> list) {for (Object element : list) {System.out.println(element);}}// 一个具体的泛型方法调用示例,用于创建并返回一个包含数字的列表public static List<Integer> createListWithNumbers(Integer... numbers) {return createListWithElements(numbers); // 这里再次调用了泛型方法createListWithElements,并进行了类型推断}
}
五、Java包装类与泛型实战
在实际开发中,包装类与泛型经常一起使用。例如,当需要将基本数据类型存储在集合中时,由于集合的泛型参数必须是对象类型,因此需要使用包装类。
import java.util.ArrayList;
import java.util.List;public class WrapperAndGenericsExample {public static void main(String[] args) {// 创建一个存储Integer对象的列表List<Integer> integerList = new ArrayList<>();integerList.add(10);integerList.add(20);integerList.add(30);// 遍历列表并打印元素for (Integer integer : integerList) {System.out.println(integer);}// 创建一个存储Double对象的列表List<Double> doubleList = new ArrayList<>();doubleList.add(1.1);doubleList.add(2.2);doubleList.add(3.3);// 使用泛型方法来打印Double列表printList(doubleList);}// 泛型方法,用于打印列表中的元素public static <T> void printList(List<T> list) {for (T element : list) {System.out.println(element);}}
}
相关文章:

深入理解Java包装类与泛型的应用
今天我将带领大家进入Java包装类和泛型应用的学习。 我的个人主页 我的Java-数据结构专栏 :Java-数据结构,希望能帮助到大家。 一、Java包装类基础 二、Java泛型基础 三、Java包装类与泛型的结合 四、Java泛型进阶 五、Java包装类与泛型实战 一、Ja…...
【机器学习chp4】特征工程
推荐文章1,其中详细分析了为什么L1正则化可以实现特征选择(特征剔除) 【王木头 L1、L2正则化】三个角度理解L1、L2正则化的本质-CSDN博客 推荐文章2,里面详细分析了奇异值分解 【线性代数】矩阵变换-CSDN博客 本文遗留问题&#…...

LeetCode螺旋矩阵
快一个月没刷题了,最近工作有些忙,今天闲下来两小时,刷一道 题目描述 给你一个 m 行 n 列的矩阵 matrix ,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。 示例 1: 输入:matrix [[1,2,3],[4…...

第十五届蓝桥杯JAVA的B组题目详情解析
(第一个填空太简单,就不写了,根本不用代码,直接excel计算) 目录 蓝桥杯第二个填空,类斐波那契循环数 蓝桥杯JAVA.b组第三题 -分布式队列(模拟) 食堂(蓝桥杯D题) 编辑 星际旅行(Floyd佛洛依德) 其余的有点变态,感觉学了好像…...

在几分钟内将数据从 Oracle 迁移到 ClickHouse
ClickHouse 是一个开源的面向列的数据库管理系统。它在实时数据处理方面的出色性能显着增强了数据分析和业务洞察力。将数据从 Oracle 迁移到 ClickHouse 可以释放数据在决策中的力量,这是单独使用 Oracle 无法实现的。 本教程介绍如何使用 BladePipe 将数据从 Orac…...

ASP.NET MVC宠物商城系统
该系统采用B/S架构,使用C#编程语言进行开发,以ASP.NET MVC框架为基础,以Visual Studio 2019为开发工具,数据库采用SQL Server进行保存数据。系统主要功能包括登录注册、宠物展示、个人中心、我的订单、购物车、用户管理、宠物类别…...

完整http服务器
目录 背景目标描述技术特点开发环境WWW客户端浏览发展史服务端http发展史http分层概览 背景 http协议被广泛使用,从移动端,pc浏览器,http无疑是打开互联网应用窗口的重要协议,http在网络应用层中的地位不可撼动,是能…...

【专题】2024AIGC创新应用洞察报告汇总PDF洞察(附原数据表)
原文链接:https://tecdat.cn/?p38310 在科技日新月异的今天,人工智能领域正以前所未有的速度发展,AIGC(人工智能生成内容)成为其中最耀眼的明珠。从其应用场景的不断拓展,到对各行业的深刻变革࿰…...

形态学图像处理(Morphological Image Processing)
形态学图像处理(Morphological Image Processing) 前言 本博客为个人总结数字图像处理一课所写,并给出适当的扩展和相应的demo。 写博客跟做 checkpoint 很像,毕竟个人还不能达到那种信手拈来的境界,忘了就是从零开始训练࿰…...

【IDER、PyCharm】免费AI编程工具完整教程:ChatGPT Free - Support Key call AI GPT-o1 Claude3.5
文章目录 CodeMoss 简介CodeMoss 的模型集成如何安装和配置 CodeMossIDER 插件安装步骤 CodeMoss 的实战使用AI 问答功能代码优化与解释优化这段代码解释这段代码 文件上传与对话联网查询与 GPT 助手联网查询GPT 助手 提升开发效率的最佳实践结语更多文献 CodeMoss 简介 CodeM…...

C++11的一些实用特性
1.统一的列表初始化 在C98中,标准允许使用花括号{}对数组或者结构体元素进行统一的列表初始值设定。 //统一的列表初始化 struct Date {int year;int month;int day; };void test1() {Date d1 { 2024,11,14 };int array1[] { 1, 2, 3, 4, 5 };int array2[5] { …...

23种设计模式-观察者(Observer)设计模式
文章目录 一.什么是观察者模式?二.观察者模式的结构三.观察者模式的应用场景四.观察者模式的优缺点五.观察者模式的实现(C示例)六.观察者模式的实现(JAVA示例)七.代码解释八.总结 类图: 观察者设计模式类图…...

【CUDA】Branch Divergence and Unrolling Loop
目录 一、避免分支发散 1.1 并行规约问题 1.2 并行规约中的发散 二、UNrolling Loops 一、避免分支发散 控制流有时依赖于 thread 索引。同一个warp中,一个条件分支可能导致性能很差。通过重新组织数据获取模式可以减少或避免 warp divergence。具体问题查看下…...
深度学习:卷积神经网络的计算复杂度,顺序操作,最大路径长度
卷积层的计算复杂度 在深度学习中,卷积层的计算复杂度主要取决于卷积核的大小、输入和输出的通道数量、以及输入序列的长度。具体来说,卷积层的计算复杂度可以通过以下几个因素来计算: 卷积核大小 k:卷积核的大小决定了每次卷积操…...
springboot 配置文件中 multipart.max-file-size 各个版本的写法
由于springboot具有几个版本,不同版本对于文件上传最大限制的配置也有所不同。 所以要注意springboot本身的版本,不然会一直报错 在springboot1.3版本中: multipart.maxFileSize在springboot1.4与springboot1.5版本中: spring…...

linux 中mysql查看慢日志
1、到mysql容器,先登录到数据库,查看是否开启 mysql -h 127.0.0.1 -uroot -p SHOW VARIABLES LIKE slow_query_log; 2、如果没有开启,需要先开启 set global slow_query_log ON; 3、查看慢日志文件 SHOW VARIABLES LIKE slow_query_log…...
单片机的基本组成与工作原理
单片机(Microcontroller Unit, MCU)是一种将计算机的主要部分集成在一个芯片上的小型计算机系统。它通常包括中央处理器(CPU)、存储器(Memory)、输入输出接口(I/O Ports)、定时器/计…...
智慧隧道和智慧交通
通过引入先进的物联网技术,将各种硬件设备如传感器、摄像头、控制系统等有效地连接并管理起来,以实现道路安全和交通流畅的目标。这些设备将能够实时监控和控制隧道内的各种设备和系统,从而提高道路安全、提升驾驶体验并降低管理成本。 在这个…...
List、Set、Map详解和区别
在 Java 中,List、Set、Map是常用的集合类型,它们各自具有不同的特点和用途,以下是对它们的详细介绍及区别分析: List(列表) 特点: 有序性:List中的元素是有序的,即元素…...

界面控件DevExpress WinForms v24.2新功能预览 - 支持.NET 9
DevExpress WinForms 拥有180组件和UI库,能为Windows Forms平台创建具有影响力的业务解决方案。DevExpress WinForms能完美构建流畅、美观且易于使用的应用程序,无论是Office风格的界面,还是分析处理大批量的业务数据,它都能轻松胜…...

MPNet:旋转机械轻量化故障诊断模型详解python代码复现
目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...
golang循环变量捕获问题
在 Go 语言中,当在循环中启动协程(goroutine)时,如果在协程闭包中直接引用循环变量,可能会遇到一个常见的陷阱 - 循环变量捕获问题。让我详细解释一下: 问题背景 看这个代码片段: fo…...

智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql
智慧工地管理云平台系统,智慧工地全套源码,java版智慧工地源码,支持PC端、大屏端、移动端。 智慧工地聚焦建筑行业的市场需求,提供“平台网络终端”的整体解决方案,提供劳务管理、视频管理、智能监测、绿色施工、安全管…...
uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖
在前面的练习中,每个页面需要使用ref,onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入,需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...

【单片机期末】单片机系统设计
主要内容:系统状态机,系统时基,系统需求分析,系统构建,系统状态流图 一、题目要求 二、绘制系统状态流图 题目:根据上述描述绘制系统状态流图,注明状态转移条件及方向。 三、利用定时器产生时…...
Java 加密常用的各种算法及其选择
在数字化时代,数据安全至关重要,Java 作为广泛应用的编程语言,提供了丰富的加密算法来保障数据的保密性、完整性和真实性。了解这些常用加密算法及其适用场景,有助于开发者在不同的业务需求中做出正确的选择。 一、对称加密算法…...
linux 下常用变更-8
1、删除普通用户 查询用户初始UID和GIDls -l /home/ ###家目录中查看UID cat /etc/group ###此文件查看GID删除用户1.编辑文件 /etc/passwd 找到对应的行,YW343:x:0:0::/home/YW343:/bin/bash 2.将标红的位置修改为用户对应初始UID和GID: YW3…...
土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测;从基础到高级,涵盖ArcGIS数据处理、ENVI遥感解译与CLUE模型情景模拟等
🔍 土地利用/土地覆盖数据是生态、环境和气象等诸多领域模型的关键输入参数。通过遥感影像解译技术,可以精准获取历史或当前任何一个区域的土地利用/土地覆盖情况。这些数据不仅能够用于评估区域生态环境的变化趋势,还能有效评价重大生态工程…...

Mac下Android Studio扫描根目录卡死问题记录
环境信息 操作系统: macOS 15.5 (Apple M2芯片)Android Studio版本: Meerkat Feature Drop | 2024.3.2 Patch 1 (Build #AI-243.26053.27.2432.13536105, 2025年5月22日构建) 问题现象 在项目开发过程中,提示一个依赖外部头文件的cpp源文件需要同步,点…...
Angular微前端架构:Module Federation + ngx-build-plus (Webpack)
以下是一个完整的 Angular 微前端示例,其中使用的是 Module Federation 和 npx-build-plus 实现了主应用(Shell)与子应用(Remote)的集成。 🛠️ 项目结构 angular-mf/ ├── shell-app/ # 主应用&…...