java中的自动装箱封箱的一些细节性的问题

今天发现了一个细节性的问题,随后自己查看源码以及一步步的分析,同时也百度别人的文章看看,所以做了下面的总结。

/* java自动装箱拆箱的细节性问题

 */
public class test {
	public static void main(String[] args) {
		Integer a = 100;
		Integer b = 100;

		Integer c = 128;
		Integer d = 128;

		System.out.println(a == b);//1
		System.out.println(a == 100);//2

		System.out.println(c == d);//3
		System.out.println(c == 128);//4
	}
}

这是一个装箱拆箱的问题。说实话,自己拿不准,所以自己运行了。

“==”比较的是object的reference而不是value,自动装箱后abcd都是Integer这个Object,因此‘’==‘’比较的是其引用。按照常规的思维,1和3
都应该是false。但是其结果却是

true
true
false
true
结果2和4都应为ac进行了自动拆箱,因此其比较的是基本数据类型的比较,就跟int比较的时候是一样的。“==”在这里比较的是他们的值,而不是引用。

    对于结果1,虽然比较的时候还是比较的是对象的reference,但是自动装箱的时候,java在编译时Integer a = 100;被翻译为Integer a =Integer.valueOf(100);关键这个valueOf的方法。

    public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }
根据上面的jdk源码,java为了提高效率,IntegerCache类中有一个数组缓存了值从-128到127的Integer对象。当我们调用Integer.valueOf(int i)的时候,如果i的值是>=-128且<=127时,会直接从这个缓存中返回一个对象,否则就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(255-128),也就是newl一个Integer(127) ,并把引用赋值给cache[255],好了,然后是Integer b= 127,流程基本一样,最后又到了cache[255] = new Integer(255-128),这一句,那我们迷糊了,这不是又new了一个对象127吗,然后把引用赋值给cache[255],我们比较这两个引用(前面声明a的时候也有一个),由于是不同的地址,所以肯定不会相等,应该返回false啊!呵呵,这么想你就错了,请注意看for语句给cache[i]初始化的时候外面还一个{}呢,{}前面一个大大的static关键字,是静态的,那么我们就可以回想下static有什么特性了,只能初始化一次,在对象间共享,也就是不同的对象共享同一个static数据。 
        那么当我们Integer b = 127的时候,并没有new出一个新对象来,而是共享了a这个对象的引用,记住,他们共享了同一个引用!!!,那么我们进行比较a==b时,由于是同一个对象的引用(她们 在堆中的地址相同)自然也就是返回true了。下面我们再来分析一下如下的代码问题:
  public class Test {
        	public static void main(String args[]){
        	Integer m = new Integer(5);
        	Integer n = new Integer(5);
        	System.out.println(m==n);
        	m = m-1;
        	n = n-1;
        	System.out.println(m==n);
        	}
        } //输出什么呢??
false
true
        原因:m,n因为都是new出来的对象,内存地址不一样,所以第一次m==n比较的reference不一样。
但是,m=m-1首先进行了自动拆箱m.intValue,相减后再进行装箱动作:m=Integer.valueOf(m.intValue-1),
而m和n都在 -128--127的范围,所以自动装箱后,根据上文所述,都是同一个object的引用。
因此第二次输出true。
再看一次(出自 java解惑
public class TestWhile{ 
	public static void main(String[] args){
		Integer i=0;
		Integer j=0;
 		Integer i=new Integer(0);
		Integer j=new Integer(0);
		while(i<=j & i>=j & i!=j){ 
			System.out.println("0000");
		}
	}
}
那一行是拆箱?while循环里的条件看似不成立,可为什么可以运行(去掉第5、6行的注释后)?
解答这种情况下,循环不能运行对于Integer类型,<,<=,>,>=操作将导致拆箱操作,
也就是调用Integer的intValue()方法得到相应的基本类型值,然后比较。
但是,==,!=比较的,是对象的引用(Reference)。
Integer i = 0;
Integer j = 0;
  这两句使用装箱操作,也就是调用Integer.valueOf(int i);注意,不是使用new。 
        由于0在 -128--127之间,根据上述,i和j引用的是同一个对象。 
        综上,i<=j & i>=j & i!=j中, 
        i<=j 和 i>=j都成立,而i!=j不成立,因为i和j引用的是同一个对象。 
        故此,循环不会执行。 
        注释掉3,4两句,使用5,6两句时,i和j引用的不是同一个对象,所以i!=j成立。i<=j & i>=j & i!=j成立,循环条件总是成立的,while (i <= j & i >= j & i != j)成为无穷循环,不断输出。 
        原题: 
        循环者的诅咒 
        请提供一个对i的声明,将下面的循环转变为一个无限循环:
 while (i <= j && j <= i && i != j) { 
   } 
        总结,对于要比较Object的值,最稳妥的方法还是调用equals()这个方法,而不是使用==,因此会比较其引用。 
      
 public boolean equals(Object obj) {
        	if (obj instanceof Integer) {
        	return value == ((Integer)obj).intValue();
        	}
        	return false;
        }
大家可以看到,只要两个Integer的int value是相等的,equals方法总是返回true。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值