-
基本数据类型和对应的包装类
基本数据类型 | 包装类 |
---|---|
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
char | Character |
boolean | Boolean |
其中double 和float两种浮点型包装类不具有常量池技术。
什么是常量池技术?
基本概念
- 为什么要设计字符串常量池?因为字符串的创建要耗费大量的时间和空间,频繁创建字符串影响程序性能。
- 创建(无论是直接赋值,还是new对象)字符串时,首先会判断字符串常量池是否有该字符串,如果有会直接引用,如果没有才会实例化该字符串,并放入常量池
例如:Integer i1 = 40;Java在编译的时候会直接将代码封装成Integer i1 = Integer.valueOf(40);
从而直接使用常量池中的对象,而不是像 Integer i1 = new Integer(40);这种情况下会创建新的对象。
但是注意这些包装类默认创建的缓存数据只适用与[-128.127]这个范围,若超出任然会去创建新的对象。
Integer i5 = 128;
Integer i6 = 128;
System.out.println(i5 == i6);//false 因为 超过了一个字节的范围 会new 一个Integer对象
System.out.println(i5.equals(i6));
System.out.println("-----------");
Integer i7 = 127;
Integer i8 = 127;
System.out.println(i7 == i8);//true 没有超过一个字节的范围 因为在方法区中存在一个 字节常量池 范围-128---127
System.out.println(i7.equals(i8));
例题:
Integer a = 128;
Integer b = 128;
Integer a2 = 127;
Integer b2 = Integer.valueOf(127);
System.out.println(" a == b:" +(a == b));
System.out.println(" a2 == b2:" + (a2 == b2));
Integer c = new Integer(128);
System.out.println(" b=c:" + (b == c));
System.out.println(" b=c.Intner:" + (b == Integer.valueOf(128)));
Integer d = 127;
Integer e = new Integer(127);
System.out.println(" d==e:" + (d == e));
System.out.println(" d = Integer.valueOf" + (d == Integer.valueOf(127)));
System.out.println(" e = Integer.valueOf" + (e == Integer.valueOf(127)));
System.out.println(" e.equals(d):" + e.equals(d));
// 执行结果
1> a == b:false
2> a2 == b2:true
3> b=c:false
4> b=c.Intner:false
5> d==e:false
6> d = Integer.valueOf true
7> e = Integer.valueOf false
8> e.equals(d):true
分析
1>使用=号赋值,导致强制拆包装,查看字节码文件,可知调用了Integer.valueOf方法。
调用了Integer.valueOf方法,下面是该方法方法体,可知,如果缓存里有该值,则返回缓存里对象,没有则创建一个新的对象。因为Integer缓存存放[-128,127]之间的数,所以1>为false。
2> a2=127自动拆装箱等于调用Integer.valueOf()方法,所以等于b2直接使用Integer.valueOf()方法
3> c是直接new对象,存放的是新的内存地址,b=128不在缓存范围中,因此也是直接new Integer,两个对象在内存中的地址不一样,所以false。
4> 与3>情况类似
5> d=127使用自动拆装箱,会到缓存中获取,e为new对象,所以不相同
6> 因为自动拆装箱其实本质也是调用Integer.valueOf()方法,所以,为true
7> e为new对象,Integer.valueOf(127)是获取缓存中的对象,因此false
8> 在阿里java泰山版中,有这样一段话
对于包装类的两个变量的比较推荐使用equals进行(比较的是值而不是地址)
说明中已经说明了原因,我就不再赘述,我们一起来看一下equals方法
实际就是value和intValue进行比较,我们来看一下intValue()和value
其实就是Integer对象里维护的final常量int值,该int值在对象被加载时,存放在方法区的元空间中(jdk1.8叫法),所以,equals比较的就是这两个int值,不论是直接复制,new对象,调用Integer.valueOf方法,只要是同一个数字,就都相等,所以为true.