我们都知道JDK其实给我们提供了很多Java开发者写好的现成类。它们其实可以理解为工具类,比如我们常见的集合类,日期相关类,数学相关类等。有了这些工具类,你会发现可以为你节省很多时间,很容易实现你的需求。方便地。当然,没有这些包你也可以实现你的需求,但是你需要时间。今天我们主要学习包装类。一、包装类介绍1、为什么需要包装类?我们知道Java语言是一种面向对象的编程语言,但是Java中的基本数据类型并不是面向对象的,但是我们在实际使用中往往需要将基本数据类型转换为对象以便于操作。比如在集合的操作中,这时候我们需要将数据的基本类型转化为对象,于是就出现了包装类。2.什么是包装类?包装类,顾名思义就是包装了一些东西的类,那么它包装的是什么东西呢?显然,这是一个包装基本类型的类。包装类的作用是将基本类型转化为对象,把基本类型当作对象来对待。在Java中,我们知道有8种基本数据类型,所以也有8种对应的包装类,包装类就是基本类型名的首字母大写。但Integer和Character除外,它们显示全名,如下表所示:基本数据类型对应封装类byteByteshortShortintIntegerlongLongfloatFloatdoubleDoublecharCharacterbooleanBoolean2.封装类的继承关系通过阅读Java8官方API文档或查看源码代码,我们可以知道8个封装类的继承关系如下:通过上面的继承关系图,我们其实可以记住封装类中有6个数字是和Number类相关的,另外两个是与数字无关的默认继承自Object类。通过查看官方API文档,我们也可以了解到这8个包装类都实现了Serializable和Comparable接口。比如下图中的Integer类publicfinalclassIntegerextendsNumberimplementsComparable{}3.包装类的使用方法(基本操作)下面我就包装类的讲解来说说Integer包装类。是的,只是一个不同的名字。1、包装类的构造方法8个包装类都有自己的构造方法,有自己对应的类型参数。其中,除了Character之外,8个封装类中还有重载的构造方法,参数都是String类型。Integerone=newInteger(666);Integertwo=newInteger("666");2、包装类的自动拆箱在了解自动拆箱之前,我们首先要知道什么是拆箱和装箱。拆包其实主要是处理基本类型和包装类型之间的相互转换。装箱:将原始类型转换为包装器类型的过程称为装箱。拆箱:将包装类型转换为原始类型的过程称为拆箱。其实在JDK1.5版本之前,是没有自动解包解包的。开发者不得不手动拆箱://手动装箱,即把基本类型10转为引用类型Integerinteger=newInteger(10);//或Integerinteger1=Integer.valueOf(10);//手动拆箱,即将引用类型转换为基本类型intnum=integer.intValue();JDK1.5版本之后,为了减少开发者的工作量,提供了自动装箱和自动拆箱的功能。实现了自动拆箱和自动装箱,如下代码所示://automaticboxingIntegerone=1;//自动拆箱inttwo=one+10;其实以上两种方式本质上是一样的,只不过一种是自动的,一种是手动的。至于如何实现自动拆箱,这里不做深入研究。4.封装类的缓存机制我们先看下面的代码,例子一:系统。out.println(i1==i2);//trueSystem.out.println(i1==i3);//falseSystem.out.println(i3==i4);//falseSystem.out.println(i1.equals(i2));//trueSystem.out.println(i1.equals(i3));//trueSystem.out.println(i3.equals(i4));//true}当我们修改值为200时,例2:publicstaticvoidmain(String[]args){Integeri1=200;Integeri2=200;Integeri3=newInteger(200);Integeri4=newInteger(200);System.out.println(i1==i2);//falseSystem.out。println(i1==i3);//falseSystem.out.println(i3==i4);//falseSystem.out.println(i1.equals(i2));//trueSystem.out.println(i1.equals(i3));//trueSystem.out.println(i3.equals(i4));//true}通过上面代码的两端,我们发现修改了值,第五行的执行结果代码已更改。为什么?什么?首先我们要明确一点,第一行和第二行代码实际上实现了自动装箱的过程,也就是自动实现了Integer.valueOf方法。其次,==比较的是地址,而equals比较的是值(这里的eauals是改写的,所以比较的是具体的值),所以显然最后五行代码的执行结果是没有疑问的。既然==比较的是地址,为什么例1中的第五行代码为真呢?这就需要我们了解包装类的缓存机制。其实查看Integer类的源码,我们可以发现在780行有一个privatestatic内部类,如下:127;StringintegerCacheHighPropValue=太阳杂项。VM.getSavedProperty("java.lang.Integer.IntegerCache.high");if(integerCacheHighPropValue!=null){try{inti=parseInt(integerCacheHighPropValue);i=Math.max(i,127);//MaximumarraysizeisInteger.MAX_VALUEh=Math.min(i,Integer.MAX_VALUE-(-low)-1);}catch(NumberFormatExceptionnfe){//如果属性不能解析成int,则忽略。}}hhigh=h;cache=newInteger[(high-低)+1];intj=low;for(intk=0;k=127;}privateIntegerCache(){}}我们知道,静态内部类是在整个Integer加载的时候加载的。上面代码初始化了一个Integer类型的数组cache,取值范围为[-128,127]。缓存机制的作用是提前实例化对应范围值的包装类对象。只要创建了缓存范围内的对象,就会使用实例化的对象。这样,避免了重复创建多个相同的包装类对象,提高了使用效率。如果我们使用的对象范围在[-128,127]以内,我们就直接去静态区找对应的对象。如果我们使用的对象的范围超出了这个范围,它会帮我们创建一个新的Integer对象。其实下面这就是源码的意思:}所以示例1代码中,i1和i2为100,取值范围为[-128,127],所以在direct区中找到静态区,所以i1和i2指向的地址相同,所以i1==i2;而在例2的代码中,i1和i2都是200,取值范围不在[-128,127],所以新建一个对象放在堆内存中,各自指向不同的地址,所以地址不同。当然,i1不等于i2。通过分析源码可以发现,只有double和float自动装箱代码没有使用缓存,每次new一个对象都是new,其他6种基本类型都使用了缓存策略。使用缓存策略是因为这些缓存的对象经常使用(例如字符,-128到127之间的数字),防止每次执行自动装箱时都创建对象的实例。5.包装类和基本数据类型的区别(1)默认值不同。包装类的默认值为null,而基本数据类型是对应的默认值(例如整数类型的默认值为0,浮点型的默认值为0.0)(2)不同存储区的基本数据类型将值保存在栈内存中,包装类将对象放在堆中,然后通过对象的引用来调用它们(3)传输方式不同。基本数据类型在变量空间中存储的是一个值,传递的也是一个值。一个变了,一个不变,而包装类属于引用数据类型。变量空间存放的是地址(引用),传递的也是引用。一个改变,另一个随之改变。五、小结以上是我个人对Java封装类的理解。其实学习这些工具类还有更好的方法,就是看官方文档(API官方文档地址:https://docs.oracle.com/javase/8/docs/api/)