为什么基本类型需要包装类
基本数据类型方便、简单、高效,但泛型不支持、集合元素不支持
不符合面向对象思维
包装类提供很多方法,方便使用,如 Integer 类 toHexString(int i)、parseInt(String s) 方法
Long 或 Integer 如何比较大小?
错误方法
使用==。 因为 Long 与 Ineger 都是包装类型,是对象。 而不是普通类型 long 与 int
使用 equals 方法。因为 equals 方法只能比较同类型的类,例如两个都是 Integer 类型。
正确方法
先使用 longValue()或 intValue()方法来得到他们的基本类型的值然后使用==比较也是可以的。
拆箱与装箱原理
装箱就是将基本数据类型转化为包装类型,那么拆箱就是将包装类型转化为基本数据类型。
1 2 3 4 5 6 7 8 public class Demo { public static void main (String[] args) { Integer a = 10 ; int b = a; } }
Integer a = 10;执行代码的时候,系统为我们执行了:Integer a = Integer.valueOf(10);
int b = a;执行代码的时候,系统为我们执行了:int b = a.intValue();
实例:自动拆装箱
实例 1:基本类型与其包装类
1 2 3 4 5 6 7 8 9 10 11 12 public class Demo { public static void main (String[] args) { int int1 = 12 ; int int2 = 12 ; Integer integer1 = new Integer (12 ); Integer integer2 = new Integer (12 ); System.out.println("int1 == int2 : " + (int1 == int2)); System.out.println("int1 == integer1 : " + (int1 == integer1)); System.out.println("integer1 == integer2 : " + (integer1 == integer2)); } }
运行结果
1 2 3 int1 == int2 : true int1 == integer1 : true integer1 == integer2 : false
Integer 是 int 的封装类,当 Integer 与 int 进行==比较时,Integer 就会拆箱成一个 int 类型,所以还是相当于两个 int 类型进行比较,这里的 Integer 不管是直接赋值,还是 new 创建的对象,只要跟 int 比较就会拆箱为 int 类型,所以就是相等的。
实例 2:自动拆箱引起的异常
首先思考,下边的程序会输出什么
1 2 3 4 5 6 public class Demo { public static void main (String[] args) { Integer a = null ; System.out.println(2 == a); } }
结果
1 2 Exception in thread "main" java.lang.NullPointerException at com.example.a.Demo.main(Demo.java:6)
原因:
因为是基本类型与包装类型进行比较,此时会将包装类型自动拆箱,调用a.intValue()获得其基本类型的值,但 a 是 null,所以报空指针异常。
实例 3:基本类型与 Object
1 2 3 4 5 6 7 8 9 10 public class Demo { public static void main (String[] args) { Object object = true ; System.out.println(object); boolean b = (boolean )object; System.out.println(b); System.out.println(b == true ); } }
运行结果
实例:实例化顺序
1 2 3 4 5 6 7 8 9 10 11 12 public class Demo { public static void main (String[] args) { int int1 = 12 ; Integer integer1 = new Integer (12 ); Integer integer2 = new Integer (34 ); int int2 = 34 ; System.out.println("int1 == integer1 : " + (int1 == integer1)); System.out.println("int2 == integer2 : " + (int2 == integer2)); } }
执行结果(不影响)
1 2 int1 == integer1 : true int2 == integer2 : true
实例:区域问题
1 2 3 4 5 6 7 public class Demo { public static void main (String[] args) { Integer integer1 = new Integer (12 ); Integer integer2 = 12 ; System.out.println("integer1 == integer2 : " + (integer1 == integer2)); } }
执行结果
1 integer1 == integer2 : false
实例:缓存问题
测试代码
1 2 3 4 5 6 7 8 9 10 public class Demo { public static void main (String[] args) { Integer a = 127 ; Integer b = 127 ; Integer c = 128 ; Integer d = 128 ; System.out.println(a == b); System.out.println(c == d); } }
执行结果
Integer 有个缓存,原理如下。
valueOf 源码
1 2 3 4 5 6 7 8 9 // private static class IntegerCache { // static final int low = -128; // static final int high = 127; // } public static Integer valueOf(int i) { if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); }
当 i 的值位于[-128,127]的时候,会直接返回 Integer 缓存数组中相应对象的引用,如果 i 大于 127 或小于-128,会重新创建一个 Integer 实例,并返回。
那么第一条式子 a 和 b 的值都在缓存范围内,因此他们指向同一个对象,因此返回 true。c 和 d 的值不在范围内,都是通过 new 创建出来的,因此不是同一个对象,返回 false。
其他包装类的缓存
Byte、Short、Integer、Long、Character 的 valueOf()实现机制类似。
包装类 说明
Byte: 相同值的 Byte 比较永远返回 true。因为 byte 取值范围就是[-128,127]。
Short、Integer、Long 相同值在[-128,127]则返回 true,不在则返回 false
Character 要返回 true,只需保证 i <= 127。因为 char 最小值为 0,本来就大于等于-128。
Float、Double 永远返回 false。因为其永远返回新创建的对象,因为一个范围内的整数是有限的,但是小数却是无限的,无法保存在缓存中。
Boolean 只有两个对象,要么是 true 的 Boolean,要么是 false 的 Boolean,只要 boolean 的值相同,Boolean 就相等。
实例:效率问题
1 2 3 4 5 6 7 8 9 10 11 public class Demo { public static void main (String[] args) { long t1 = System.currentTimeMillis(); Long sum = 0L ; for (int i = 0 ; i < Integer.MAX_VALUE; i++) { sum += i; } long t2 = System.currentTimeMillis(); System.out.println(t2 - t1); } }
上述代码,结果为:6218
如果将 sum 改为 long 型,结果为:624
可见效率差别之大