目录
为什么Integer类型的a1 == a2为true,其中a1和a2的值为10,而a3 == a4为false,a3和a4的值为1000
什么是包装类
包装类的定义
包装类(Wrapper Class)是Java编程语言中的一个重要概念,用于将基本数据类型封装为对象类型。Java是一种面向对象的编程语言,但其基本数据类型(如int、byte、float等)并不支持面向对象的特性,如继承、多态等。为了弥补这一不足,Java为每种基本数据类型都提供了一个对应的包装类,这些包装类位于java.lang包中。包装类的主要作用是允许基本数据类型像对象一样使用。
具体来说,Java中的八种基本数据类型及其对应的包装类如下:
包装类与基本数据类型的区别
包装类与基本数据类型的区别主要在于包装类本质上是一个类,因此它是一个引用数据类型,而基本数据类型是存储在栈中的原始值类型。
直接存储数值,存储在栈中,效率高,但是不具备对象的特性。例如,int类型的变量a = 10,只是在内存中存储了数值10。
存储在堆中,可以为基本数据类型提供更多的方法和属性,具有面向对象的特性。例如,Integer类型的变量a1 = 10是一个对象,除了存储数值10,还可以调用equals()等方法。
举例来说,int类型的10与Integer类型的10有以下不同:
Integer是一个类,不仅能够表示数值10,还包含许多方法,例如可以调用equals()方法,而int只能通过==进行值的比较。
Integer类型的特点
为什么Integer类型的a1 == a2为true,其中a1和a2的值为10,而a3 == a4为false,a3和a4的值为1000
public class Test {
public static void main(String[] args) {
Integer a1 = 10;
Integer a2 = 10;
System.out.println(a1 == a2); // 输出 true
Integer a3 = 1000;
Integer a4 = 1000;
System.out.println(a3 == a4); // 输出 false
}
}
true
false
a1 == a2返回true,而a3 == a4返回false的原因,实际上是因为Integer的valueOf()方法。Java对于数值在-128到127之间的Integer对象会在一个缓存数组中存储,这个数组相当于一个缓存池。
当你创建一个数值在-128到127之间的Integer对象时,它会直接返回该值在数组中的地址。所以在这个范围内的数值用==比较是相等的。
而超出这个范围的数值,则会新开辟一个内存空间,因此它们的地址不同,所以比较结果为false。
128陷阱详细分析
Integer类型的一个重要方法是Integer.valueOf()。在文件中定义一个Integer类型变量,通过javac编译和javap -c反编译该文件可以发现,像Integer b = 10;这样的代码会被编译成Integer b = Integer.valueOf(10);,涉及到自动装箱。
方法在数值在-128到127之间时,会返回缓存中的相同地址的对象。如果数值不在这个范围内,则会调用new Integer()方法,开辟新的内存空间。
valueOf()方法的取值范围是通过查看代码中low和high值定义的,它们分别为-128和127。当数值在这个范围内时,valueOf()方法返回的是缓存池中对应的数值对象,这就解释了为什么a1和a2相等,而a3和a4不等。
自动拆装箱
在讨论128陷阱时,我们提到过自动拆装箱。自动拆装箱是Java中的一种特性,主要涉及基本数据类型与它们对应的封装类之间的自动转换。
自动装箱
自动装箱是指将基本数据类型自动转换为封装类对象的过程。Java自动将基本类型的值赋给相应的包装类对象,例如:
Integer b = 10; // 自动装箱
Integer b = Integer.valueOf(10);
自动拆箱
自动拆箱是指将封装类对象自动转换为基本数据类型的过程。例如:
Integer b = 10;
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); // 输出:true
System.out.println(a1 == b1); // 输出:true
System.out.println(a2 == b2); // 输出:false
System.out.println(a1 == a); // 输出:true
System.out.println(a1.equals(a)); // 输出:true
System.out.println(a1 == a2); // 输出:false
System.out.println(a == a2); // 输出:true
}
}
原因:a和b是基本数据类型,==比较的是它们的值,两个int值相等,所以结果是true。
原因:a1和b1是Integer类型,值在-128到127之间,所以从缓存中取得相同的对象引用,==比较的是内存地址,相同,所以结果是true。
原因:a2和b2使用new关键字创建,每次都会创建新的对象,所以它们的内存地址不同,==比较结果为false。
原因:a1是包装类,a是基本类型,在使用==比较时,a1会自动拆箱为int类型,然后与a进行值比较,结果是true。
System.out.println(a1.equals(a));
原因:equals()方法会判断a是否为Integer类型,然后拆箱比较值是否相同,结果是true。
原因:a1是缓存中的对象,a2是新创建的对象,内存地址不同,==比较结果为false。
原因:a2是包装类对象,a是基本数据类型,a2会自动拆箱为int类型,与a进行值比较,结果是true。
总结
包装类在Java中是一个重要的特性,允许基本数据类型拥有对象的特性,从而支持更多的操作和方法调用。理解包装类的工作原理,特别是自动拆装箱和Integer缓存机制,有助于我们更好地编写和优化Java代码。