刚才看到java手册上这部分知识挺有意思的,也写下来记录。
在java中,数据类型总共可分为两大种,基本数据类型(值类型)和引用数据类型(类类型)。基本类型的数据不是对象,所以对于要将基本数据类型作为对象来使用的情况时,java提供该类相对应的包装类。以下是8种数据类型和对应的包装类:
int-------------- integer
char----------- Character
float ----------- Float
double------- Double
byte ----------- Byte
short---------- Short
long----------- Long
boolean------ Boolean
包装类提供了很多相互转换的方法。
所谓装箱,就是使基本数据类型用ta们对应的引用数据类型包起来,使ta们可以具有对象的特质。
所谓拆箱,就是跟装箱的方向相反,将Integer和Double这样引用数据类型的对象重新简化为值类型的数据。
javase5.0提供给了自动装箱和拆箱的操作,此功能实际上是编译器在编译时依照coder编写的方法,来决定是否进行拆箱或装箱操作。
自动装箱的过程:每当需要一种类型的对象时,这种基本类型就自动地封装到与ta相同类型的包装中。
自动装箱,只需要将值付给一个类型包装器引用,java会自动创建一个对象。
example~
Integer i = 200;//没有通过使用new来显示建立,java自动完成。
自动拆箱的过程:每当需要一个值时,被装箱对象中的值就被自动的提取出来,没必要再去调用intValue()和doubleValue()方法。
example~
int i = 11;
Integer j = new Interger(i);//手动装箱操作
int k = j.intValue();//手动拆箱操作
int i = 11;
Integer j = i;//自动装箱
int k = j;//自动拆箱
在 Integer的自动装拆箱过程中的一些细节需要注意:
* 在java中,"=="比较的是object的reference而不是value,自动装箱后,abcd都是Integer
* 因此"=="比较的是其引用,按照常规可判断1,3,都为false.2,4,因为自动拆箱,比较的是基本数据的比较
* 此时"=="比较的是ta们的值,而不是引用,这不必多说。关键的是1,3。对于结果1,虽然比较的时候,
* 还是比较对象的reference,但是在自动装箱时,java在编译的时候Integer a=110;被翻译为
* Integer a =Integer.Valueof(100);
* 我们来看源码
* public static Integer valueOf(int i) {
final int offset = 128;
if (i >= -128 && i <= 127) { // must cache
return IntegerCache.cache[i + offset];
}
return new Integer(i);
}
private static class IntegerCache {
private IntegerCache(){}
static final Integer cache[] = new Integer[-(-128) + 127 + 1];
static {
for(int i = 0; i < cache.length; i++)
cache[i] = new Integer(i - 128);
}
}
根据上面的源码,java为了提高效率在IntegerCache类中有一个数组缓存了值从
-128到127的Integer对象。当我们调用Integer.Valueof(int i)时,如果值是在该范围内的
会直接从这个缓存中返回一个堆想,否则就new一个Integer对象
static final Integer cache[] = new Integer[-(-128) + 127 + 1]; //将cache[]变成静态
static {
for(int i = 0; i < cache.length; i++)
cache[i] = new Integer(i - 128); //初始化cache[i]
}
这是一个for循环对数组cache进行赋值,cache[255] = new Integer(127),然后把引用赋值给cache[255]
好了,然后是Integer b = 127,流程基本一样,最后又到了cache[255] = new Integer(255-125),这一句是不是
很迷糊,等于又new了一个对象127,然后把引用赋值给cache[255]我么比较这两个引用,由于是不同的地址,所以肯定不会相等!应该返回false!
这么想就错了,注意!for语句给cache[i]初始化的时候外面还有一对大括号,大括号前面是一个static 关键字!!
静态的static修饰的代码块,只能初始化一次,在对象中共享,也就是说不同的对象共享同一个static数据.
当我们Integer b = 127的时候,并没有new出一个新对象来,而且是共享了a这个对象的引用!!ta们共享了一个引用!!
那么我们进行比较a==b的时候,由于是同一个对象的引用,当然返回true啦!
继续看下面的代码
Integer m = new Integer(5);
Integer n = new Integer(5);
System.out.println(m==n);
m--;
n--;
System.out.println(m==n);
分别输出了 true;false.原因是m,n都是new出来的对象,内存地址不一样,所以第一次m==n进行比较的reference不一样
但是m--,n--后,进行了自动拆箱m.intValue,相减后再进行装箱操作:m = Integer.valueOf(m.intValue-1),
而m,n都是在-128~127之间的,同属一个object引用,因此第二次输出为ture。
再看下面的!
Integer i=0;//1
Integer j=0;//2
// Integer i = new Integer(0);//3
// Integer j = new Integer(0);//4
if(i<=j&i>=j&i!=j)
{
System.out.println("我赢了!");
}else{
System.out.println("---");
}
哪一行是拆箱呢?
解答:
在这种情况下,循环不能运行,<,<=,>,>=操作将导致拆箱操作,也就是调用Integer的intValue()方法得到相应的
基本类型,然后比较;
但是==,!=比较的是对象的引用(reference)
这两句使用装箱操作 (Integer.valueOf(int i))注意,不是使用new!!
由于0在该范围内,根据上述,i和j引用的是同一个对象 此时i!=j不成立,因此循环不会执行。
注释掉 第3,4 句,使用第5,6句,i和j引用的不是同一个对象,所以i!=j成立!!i<=j&i>=j&i!=j成立,循环条件
总是成立的。
总结:
只要对于比较Object的值,最稳妥的方法还是调用equals()方法,而不是使用==,因为会比较其引用。
本文详细解析了Java中自动装箱与拆箱的过程及原理,包括如何在基本数据类型和包装类之间进行转换,以及在特定数值范围内共享对象引用以提高效率。

6200

被折叠的 条评论
为什么被折叠?



