包装类型
此前提到,Java的数据类型分两种:
- 基本数据类型
- 引用数据类型
基本数据类型是有默认值的,引用数据类型可以赋值为null
,但不是基本数据类型不行。
一个int整数的时候,如果不初始化,默认就是0,但是如何把int整数数据初始化为null,而不是 0 呢?
这时候就需要用到包装类型了 。
Java核心库为每种基本类型都提供了对应的包装类型:
基本类型 | 对应的引用类型 |
---|---|
boolean | java.lang.Boolean |
byte | java.lang.Byte |
short | java.lang.Short |
int | java.lang.Integer |
long | java.lang.Long |
float | java.lang.Float |
double | java.lang.Double |
char | java.lang.Character |
基本数据类型和包装数据类型可以相互转换(null 拆箱会报NullPointerException)。
# 1、Integer 与 int
Integer
是 int
整型的包装数据类型。
Integer
比较特别,下面重点来讲讲。
我们定义一个整型的数据可以这样写:
int i =1;
Integer i = 1;
Integer i = new Integer(1);
但其背后原理是不一样的。
基本数据类型 "==" 比较的是值。
引用数据类型 "==" 比较的是地址。
# 1.1、拆箱与装箱
装箱就是自动将基本数据类型转换为包装器类型;使用Integer.valueOf
方法。
拆箱就是自动将包装器类型转换为基本数据类型;使用Integer.intValue
方法。
eg:
//自动装箱
Integer total = 99;
//这里实际是等于 Integer total = Integer.valueOf(99);
//自动拆箱
int totalprim = total;
//这里实际是等于 int totalprim = total.intValue();
# 1.2、范围问题
Integer i = 400;
Integer j = 400;
System.out.println(i==j); //false
Integer o = 12;
Integer k = 12;
System.out.println(o==12); //true
这是个很容易忽略但是必须要知道的范围问题。
上面提到,使用 Integer
去创建数据,其实是一个Integer.valueOf
过程,Integer.valueOf
源码如下:
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
如果值的范围在-128到127之间,它就从高速缓存返回实例。
否则 new 一个Integer对象。new Integer
就是一个装箱的过程了,装箱的过程会创建对应的对象,这个会消耗内存,所以装箱的过程会增加内存的消耗,影响性能。
所以说最后是i 和 j 两个对象比较,内存地址不一样,结果就是false了。
# 1.3、==的值 比较问题
int a = 200;
Integer b = new Integer(200);
Integer b1 =new Integer(200);
Integer c = 200;
System.out.println(a == b); //true
System.out.println(a == c); //true
System.out.println(b == c); //false
System.out.println(b == b1); //false ,这是两个不同的对象
a==b,a==c
,只要和基本数据类型(即 int)比较,Integer就会调用value.intValue()
拆箱成基本数据类型,你也可以理解为:当有基本数据类型时,只比较值
b==c
、b == b1
,这两个是永远不会相等的,拆箱装箱只是针对基本数据类型的比较才有,Integer并不是基本数据类型,b、c、b1 三者存放的内存地址不一样,所以不相等。
# 1.4、Integer.parseInt()和Integer.valueOf()的区别
parseInt()
和 valueOf()
都是Integer 对象的方法。入参都是一个String字符串。
- parseInt
public static int parseInt(String s) throws NumberFormatException
将字符串参数作为带符号十进制整数来转换。如果无法转换,抛出 NumberFormatException。
- valueOf
public static Integer valueOf(String s) throws NumberFormatException
返回初始化为指定 String 值的新的 Integer 对象,如果无法转换,抛出 NumberFormatException。
eg:
String str = "-12";
int num = Integer.parseInt(str);
System.out.println(num); // -12
Integer num2 = Integer.valueOf(str);
System.out.println(num2); // -12
int num3 =Integer.parseInt("HaC"); //java.lang.NumberFormatException
int 与 Integer转换:
int a = A.intValue();
Integer A = Integer.valueOf(a);
Integer派别:Integer、Short、Byte、Character、Long这几个类的valueOf方法的实现是类似的。 Double派别:Double、Float的valueOf方法的实现是类似的。每次都返回不同的对象。
# 总结1:
①、无论如何,Integer 与 new Integer不会相等。不会经历拆箱过程,因为它们存放内存的位置不一样。
②、两个都是new出来的,即两个new Integer比较,一定不会相等。
③、两个都是非new出来的Integer,如果数在-128到127之间,则是true,否则为false。
④、int与Integer、new Integer()进行==比较时,结果永远为true,因为会把Integer自动拆箱为int,其实就是相当于两个int类型比较。
# 总结2:
- Integer 继承了Object类,是对象类型,有自己的属性和方法,是 int 的包装类。int是java基本数据类型。
- Integer默认值null,int默认值 0。
- int 可以直接做运算,Integer 不能直接运算,拆箱转化为int才能进行运算。
# 2、其他包装类型
但是double有点不一样:(float也是一样)
Double的valueOf()
和Integer的valueOf()
不一样,Double是直接装箱的,new一个对象。
eg:
public class Main {
public static void main(String[] args) {
Double i1 = 100.0;
Double i2 = 100.0;
Double i3 = 200.0;
Double i4 = 200.0;
System.out.println(i1==i2); //false
System.out.println(i3==i4); //false
}
}
看一下 Double的valueOf()
方法源码:
public static Double valueOf(double d) {
return new Double(d); //直接new 对象
}
可以看到Double是直接new 一个对象的,并不像是Integer那样判断范围。
进行一个归类:
- Integer派别:Integer、Short、Byte、Character、Long这几个类的valueOf方法的实现是类似的。
- Double派别:Double、Float的valueOf方法的实现是类似的。每次都返回不同的对象。