本文主要讲解的是包装类,和128陷阱,以及在介绍包装类128陷阱时,所涉及到的自动拆装箱及其相关知识,以及一道关于上述内容的练习题。
一、什么是包装类
1、包装类定义
包装类(Wrapper Class)是Java编程语言中的一个重要概念,用于将基本数据类型封装为对象类型。Java是一个面向对象的编程语言,但基本数据类型(如int、byte、float等)并不直接支持面向对象的特性,如继承、多态等。为了弥补这一不足,Java为每种基本数据类型都提供了一个对应的包装类,这些包装类位于java.lang包中。
具体来说,Java中的八种基本数据类型及其对应的包装类如下:
2、包装类与基本数据类型的区别
包装类的本质是一个类。
例:int类型的10与Integer类型的10有什么不同?
①int只是一个数据类型,只能定义10在内存中如何存储
②Integer是一个类,其中包含很多方法,比如a1可以调用equals()方法而a只能用==所判断。
二、Integer类型的特点
1、为什么Integer类型的a1==a2为true,其中a1y与a2的值为10,a3==a4为false,a3、a4的值为1000。
(1)例:代码如下
public class Test {
public static void main(String[] args) {
Integer a1=10;
Integer a2=10;
System.out.println(a1==a2);
Integer a3=1000;
Integer a4=1000;
System.out.println(a3==a4);
}
结果:
True
Flase
原因:
包装类是引用数据类型,==在引用数据类型当中比较的是地址是否相同。
而a1==a2为true,a3==a4为false的答案就在Integer的valueOf()方法中,我们将数值在-128到127之间的数值都存储在一个catch数组当中。该数组相当于一个缓存。
数据-128-127之间直接返回该值在数组当中的地址,所以在-128-127之间的数值用==比较是相等的
而不在这个区域的数。需要新开辟一个内存空间所以不想等。即128陷阱,详细分析如下。
2、128陷阱详细分析
在Integer当中有一个比较重要的方法Integer valueOf()方法。
在文件中定义一个Integer类型变量,通过javac编译和javap -c反编译该文件发现自己定义10会被Integer调用Integer valueOf()
此时若想了解a是如何存储的只需要了解Integer valueOf(),查看该方法,发现所传的值i在某一个范围之内会执行一个条语句,而不再该范围之内则会new Integer,开辟新的内存空间。
此时就能间接的解释,为何a3与a4为何不等,因为他们在取值范围之外,导致a3与a4开辟了新的内存空间。导致两者不等。
此时在看Integer valueOf()方法的取值范围,先查看下限low,发现low的值为-128。
再看high的值,发现high的值为127。同时再看在此范围当中,会返回什么查看catch,发现catch是一个大小为256的数组,其值从-128到127。
此时发现,如果该值在-128到127之间,那么返回的是在该数组中与该值相同的同一块的值,此时就能解释a1与a2为何相同,因为二者指向同一块内存空间。而a3与a4则不在范围内,重新开辟一个新的空间。这个问题被人称为128陷阱。
三、自动拆装箱
上述分析128陷阱时涉及到自动拆装箱,一下对此进行一个补充。
自动拆装箱本身是一个方法。自动拆装箱是Java等编程语言中的一种特性,主要涉及基本数据类型(如int、double等)与它们对应的封装类(如Integer、Double等)之间的自动转换。具体来说,自动装箱是指将基本数据类型自动转换为封装类对象的过程,而自动拆箱则是将封装类对象自动转换为基本数据类型的过程。
1、自动装箱
自动装箱是指将基本数据类型自动转换为封装类对象的过程。
例如:Integer b=10;此时该代码会被编译成Integer b=Integer.valueOf(10),涉及到自动装箱。
2、自动拆箱
自动拆箱则是将封装类对象自动转换为基本数据类型的过程。
例如:Integer b=10; Int a=b;此时int a =b会被编译成int a=b.intvalue();涉及到自动拆箱。
四、练习
public class Test {
public static void main(String[] args) {
int a=10;
int b=10;
Integer a1=10;
Integer b1=10;
Integer a2=new Integer(10);
Integer b2=new Integer(10);
System.out.println(a==b);
System.out.println(a1==b1);
System.out.println(a2==b2);
System.out.println(a1==a);
System.out.println(a1.equals(a));
System.out.println(a1==a2);
System.out.println(a==a2);
}
① System.out.println(a==b);
输出:true
原因:基本数据类型==比较的是值,二者值相等返回true。
②System.out.println(a1==b1);
输出:true
原因:Integer类型中若值在-128到127之间,则从数组中找数据,==比较地址所以为true。
③System.out.println(a2==b2);
输出:false
原因:new是开辟新的空间,==比较地址所以为false。
④System.out.println(a1==a);
输出:true
原因:包装类类型与基本数据类型用==比较时,会自动拆箱,此时a1会变成int类型数据,比较值是否相同。
⑤System.out.println(a1.equals(a));
输出:true
原因:查看equals方法,发现会判断值是否是一个Integer类型如果是则进行拆箱,比较值是否相同。
⑥ System.out.println(a1==a2);
输出:false
原因:一个在数组当中,一个是new开辟新的空间,==比较地址所以为false。
⑦System.out.println(a==a2);
输出:true
原因:自动拆箱,然后进行值的比较。