已备案网站更换域名,wordpress 使用主题,小说推广渠道,自己怎么个人网站我们都知道#xff0c;JDK 其实给我们提供了很多很多 Java 开发者已经写好的现成的类#xff0c;他们其实都可以理解成工具类#xff0c;比如我们常见的集合类#xff0c;日期相关的类#xff0c;数学相关的类等等#xff0c;有了这些工具类#xff0c;你会发现它能很大…我们都知道JDK 其实给我们提供了很多很多 Java 开发者已经写好的现成的类他们其实都可以理解成工具类比如我们常见的集合类日期相关的类数学相关的类等等有了这些工具类你会发现它能很大程度的帮你节省时间能很方便的实现你的需求。当然没有这些包你也能实现你的需求但是你需要时间今天我们主要是来学习一下包装类。一、包装类介绍1、为什么需要包装类我们知道 Java 语言是一个面向对象的编程语言但是 Java 中的基本数据类型却不是面向对象的但是我们在实际使用中经常需要将基本数据类型转换成对象便于操作比如集合的操作中这时我们就需要将基本类型数据转化成对象所以就出现了包装类。2、包装类是什么呢包装类顾名思义就是将什么经过包装的类那么是将什么包装起来的呢显然这里是将基本类型包装起来的类。包装类的作用就是将基本类型转成对象将基本类型作为对象来处理。Java 中我们知道基本数据类型有8个所以对应的包装类也是8个包装类就是基本类型名称首字母大写。但Integer 和 Character 例外它们显示全称如下面表格所示基本数据类型对应包装类byteByteshortShortintIntegerlongLongfloatFloatdoubleDoublecharCharacterbooleanBoolean二、包装类的继承关系通过阅读 Java8 的 API 官方文档或者看源代码我们可以得知8个包装类的继承关系如下通过以上的继承关系图我们其实可以这样记忆包装类里面有6个与数字相关的都是继承自 Number 类而其余两个不是与数字相关的都是默认继承 Object 类。通过看 API 官方文档我们还可以得知这8个包装类都实现了Serializable , Comparable 接口。比如下图的 Integer 类public final class Integer extends Number implements ComparableInteger {}三、包装类的使用方法基本操作接下来关于包装类的讲解我就讲Integer包装类其他的都依此类推用法和操作都是差不多的只是名字不一样而已。1、包装类的构造方法8个包装类都有带自己对应类型参数的构造方法其中8个包装类中除了Character还有构造方法重载参数是String类型的。Integer one new Integer(666);Integer two new Integer(666);2、包装类的自动拆装箱在了解自动拆装箱之前我们得先知道什么是拆箱和装箱。其实拆装箱主要应对基本类型与包装类型的相互转换问题。**装箱**将基本类型转换成包装类型的过程叫做装箱。**拆箱**将包装类型转换成基本类型的过程叫做拆箱。其实在 JDK1.5 版本之前是没有自动拆装箱的开发人员要手动进行装拆箱//手动装箱也就是将基本类型10转换为引用类型
Integer integer new Integer(10);
//或者
Integer integer1 Integer.valueOf(10);
//手动拆箱也就是将引用类型转换为基本类型
int num integer.intValue();而在在 JDK1.5 版本之后为了减少开发人员的工作提供了自动装箱与自动拆箱的功能。实现了自动拆箱和自动装箱如下方代码所示//自动装箱
Integer one 1;
//自动拆箱
int two one 10;其实以上两种方式本质上是一样得只不过一个是自动实现了一个是手动实现了。至于自动拆装箱具体怎么实现的我这里不做深入研究。四、包装类的缓存机制我们首先来看看以下代码例1public static void main(String[] args) {Integer i1 100; Integer i2 100; Integer i3 new Integer(100);Integer i4 new Integer(100);System.out.println(i1 i2);
//true System.out.println(i1 i3);
//false System.out.println(i3 i4);
//false System.out.println(i1.equals(i2));
//true System.out.println(i1.equals(i3));
//true System.out.println(i3.equals(i4));
//true
}当我们修改了值为200的时候例2public static void main(String[] args) {
Integer i1 200; Integer i2 200; Integer i3 new Integer(200); Integer i4 new Integer(200);
System.out.println(i1 i2);
//false System.out.println(i1 i3);
//false System.out.println(i3 i4);
//false System.out.println(i1.equals(i2));
//true System.out.println(i1.equals(i3));
//true System.out.println(i3.equals(i4));
//true
}通过上面两端代码我们发现修改了值第5行代码的执行结果竟然发生了改变为什么呢首先我们需要明确第1行和第2行代码实际上是实现了自动装箱的过程也就是自动实现了 Integer.valueOf 方法其次比较的是地址而 equals 比较的是值这里的 eauals 重写了所以比较的是具体的值所以显然最后五行代码的执行结果没有什么疑惑的。既然比较的是地址例1的第5行代码为什么会是true呢这就需要我们去了解包装类的缓存机制。其实看Integer类的源码我们可以发现在第780行有一个私有的静态内部类如下private static class IntegerCache { static final int low -128; static final int high; static final Integer cache[];static { // high value may be configured by property int h 127; String integerCacheHighPropValue sun.misc.VM.getSavedProperty(java.lang.Integer.IntegerCache.high); if (integerCacheHighPropValue ! null) { try { int i parseInt(integerCacheHighPropValue); i Math.max(i, 127); // Maximum array size is Integer.MAX_VALUE h Math.min(i, Integer.MAX_VALUE - (-low) -1); }
catch( NumberFormatException nfe) { // If the property cannot be parsed into an int, ignore it. } } high h;cache new Integer[(high - low) 1]; int j low; for(int k 0; k cache.length; k) cache[k] new Integer(j);// range [-128, 127] must be interned (JLS7 5.1.7) assert IntegerCache.high 127; }private IntegerCache() {
}
}我们知道静态的内部类是在整个 Integer 加载的时候就已经加载完成了以上代码初始化了一个 Integer 类型的叫 cache 的数组取值范围是[-128, 127]。缓存机制的作用就是提前实例化相应范围数值的包装类对象只要创建处于缓存范围的对象就使用已实例好的对象。从而避免重复创建多个相同的包装类对象提高了使用效率。如果我们用的对象范围在[-128, 127]之内就直接去静态区找对应的对象如果用的对象的范围超过了这个范围会帮我们创建一个新的 Integer 对象其实下面的源代码就是这个意思public static Integer valueOf(int i) { if (i IntegerCache.low i IntegerCache.high) return IntegerCache.cache[i (-IntegerCache.low)]; return new Integer(i);
}所以 例1 代码里i1 和i2 是100值的范围在[-128, 127]所以直接区静态区找所以i1和i2指向的地址是同一个所以 i1i2而在例2的代码里i1 和i2 是200值的范围不在在[-128, 127]所以分别创建了一个新的对象放在了堆内存里各自指向了不同的地址所以地址都不同了自然 i1 不等于 i2。通过分析源码我们可以发现只有 double 和 float 的自动装箱代码没有使用缓存每次都是 new 新的对象其它的6种基本类型都使用了缓存策略。使用缓存策略是因为缓存的这些对象都是经常使用到的如字符、-128至127之间的数字防止每次自动装箱都创建一次对象的实例。五、包装类和基本数据类型的区别默认值不同包装类的默认值是null而基本数据类型是对应的默认值比如整型默认值是0浮点型默认值是0.0存储区域不同基本数据类型是把值保存在栈内存里包装类是把对象放在堆中然后通过对象的引用来调用他们传递方式不同基本数据类型变量空间里面存储的是值传递的也是值一个改变另外一个不变而包装类属于引用数据类型变量空间存储的是地址(引用)传递的也是引用一个变另外一个跟着变。