在jdk5以前,不能直接向集合中放入基本类型值,应为集合只接收对象。通常的做法是把这些原始类型的值转化为对象,然后将这些转化的对象再放入集合中。jdk5引入了原始类型和对象类型自动转换的装箱和拆箱机制。
自动装箱
把基本类型对应的引用类型封装起来,使它们具有对象的特征,可以调用toString()、hashCode()、equals()等方法
Integer a = 3
为自动装箱
编译器调用的是static Integer valueOf(int i)
Integer a=3 -> Integer a = Integer.valueof(3)
自动拆箱
将对象重新简化为基本类型的数据
int i = new Integer(2)
为自动拆箱
编译器调用int intValue()
返回该Integer对象的int值
自动装箱和自动拆箱都是有编译器来完成的,编译器会在编译器根据语法决定是否进行拆箱和装箱
自动装箱和拆箱的实例
自动拆装箱主要发生在两种情况下
- 赋值时
- 调用方法时
这里明确一点:不支持int[] Integer[]
数组类型的相互转化
对象的比较
在java中,例如Integer,会对-128到127的对象进行缓存,当创建新的Integer对象时,如果符合这个范围,并且已经存在相同值的对象,则返回这个对象,否则创建新的Integer对象。
在Java中另一个节省内存的例子就是字符串常量池(为了减少字符串创建的开销)
在java8中,方法区中的运行时常量池被分配到了堆中,但是堆中存的还是有字符串常量池的
String s1 = "abc";
String s2 = "abc";
System.out.println(s1==s2);//true
String s3 = new String("xyz");
String s4 = new String("xyz");
System.out.println(s3==s4);//false
- 采用字面值的方法创建字符串时,JVM首先会去字符串池中查找是否存在"abc"这个对象,如果不存在,则在字符串池中创建"abc"这个对象,然后将池中"abc"这个对象的引用地址返回给"abc"对象的引用s1,这样s1会指向池中"abc"这个字符串对象;如果存在,则不创建任何对象,直接将池中"abc"这个对象的地址返回,赋给引用s2。
- 采用new关键字新建一个字符串对象时,JVM首先在字符串池中查找有没有"xyz"这个字符串对象,如果有,则不在池中再去创建"xyz"这个对象了,直接在堆中创建一个"xyz"字符串对象,然后将堆中的这个"xyz"对象的地址返回赋给引用s3,这样,s3就指向了堆中创建的这个"xyz"字符串对象;如果没有,则首先在字符串池中创建一个"xyz"字符串对象,然后再在堆中创建一个"xyz"字符串对象,然后将堆中这个"xyz"字符串对象的地址返回赋给s3引用,这样,s3指向了堆中创建的这个"xyz"字符串对象。s4则指向了堆中创建的另一个"xyz"字符串对象。s3 、s4是两个指向不同对象的引用,结果当然是false。
即,每次新建String对象都要向池中查询后添加
预缓存值
Byte Integer Short Long对应的是-128到127
Character对应的0到127
Float和Double没有自动装箱池
总结
- Integer == int自动拆箱
- Integer > < Integer 自动拆箱
- Integer == Integer 比较两个对象的地址,但是当对象在-128到127时,由于用到的是缓存对象,所以对象是相等的,对这类对象的比较我们最好重写equals方法