JAVA Integer的一点注意事项

本文详细解析了Java中Integer对象的自动装箱机制,通过源码分析,揭示了Integer.valueOf(int i)方法内部实现,以及如何在-128到127的整数范围内复用对象实例,避免不必要的内存分配。

        用==比较2个Integer对象时,有些小细节需要注意的。Integer,Short,Long和String都是常量类,用final修饰class,声明时可以直接赋值,也可以new,他们之间有什么区别呢?关于String,可以看我的另一篇博文http://blog.youkuaiyun.com/dream_broken/article/details/8759616,在这就不多说了。下面就拿Integer说说,Short,Long都是差不多的(Double不是).

       好了,先直接上源码。

public class TestInt {

	public static void main(String[] args){
		Integer c=100,d=100;
		Integer e=1000,f=1000;
		Integer g=new Integer(100);
		Integer h=new Integer(100);
		Integer j =new Integer(1000);
		Integer k =new Integer(1000);
		System.out.println(c==d);
		System.out.println(e==f);
		System.out.println(g==h);
		System.out.println(j==k);
		System.out.println(e==j);	
	}
}

  如果你都对了,并且知道理由,那你可以关闭该网页了。

   运行结果:

true
false
false
false
false

       我做的时候,错了e==f的判断。其它的使用了new的,相信大家也不会错,因为==比较的是引用值,而使用了new说明在堆(Eden区)创建一个新对象。那么为什么c==d成立,而e==f不成立呢。

      我第一件事就是用javap -verbose查看class文件。

public static void main(java.lang.String[]);
  Code:
   Stack=3, Locals=9, Args_size=1
   0:	bipush	100
   2:	invokestatic	#16; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
   5:	astore_1
   6:	bipush	100
   8:	invokestatic	#16; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
   11:	astore_2
   12:	sipush	1000
   15:	invokestatic	#16; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
   18:	astore_3
   19:	sipush	1000
   22:	invokestatic	#16; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
   25:	astore	4
   27:	new	#17; //class java/lang/Integer
   30:	dup
   31:	bipush	100
   33:	invokespecial	#22; //Method java/lang/Integer."<init>":(I)V
   36:	astore	5
   38:	new	#17; //class java/lang/Integer
   41:	dup
   42:	bipush	100
   44:	invokespecial	#22; //Method java/lang/Integer."<init>":(I)V
   47:	astore	6
   49:	new	#17; //class java/lang/Integer
   52:	dup
   53:	sipush	1000
   56:	invokespecial	#22; //Method java/lang/Integer."<init>":(I)V
   59:	astore	7
   61:	new	#17; //class java/lang/Integer
   64:	dup
   65:	sipush	1000
   68:	invokespecial	#22; //Method java/lang/Integer."<init>":(I)V
   71:	astore	8
   73:	getstatic	#25; //Field java/lang/System.out:Ljava/io/PrintStream;
   76:	aload_1
   77:	aload_2


    发现:对于Integer x=500这形式的声明并赋值,都调用了Integer类中的静态方法Integer.valueOf(int i);对于Integer x=new Integer(500)这形式的,直接调用构造器.

   再把class文件反编译看看源码。

public class TestInt
{
  public static void main(String[] args)
  {
    Integer c = Integer.valueOf(100); Integer d = Integer.valueOf(100);
    Integer e = Integer.valueOf(1000); Integer f = Integer.valueOf(1000);
    Integer g = new Integer(100);
    Integer h = new Integer(100);
    Integer j = new Integer(1000);
    Integer k = new Integer(1000);
    System.out.println(c == d);
    System.out.println(e == f);
    System.out.println(g == h);
    System.out.println(j == k);
    System.out.println(e == j);
  }
}


            到了这,非常明白了,原来是编译器做了处理。那么对于c==d成立,e==f不成立的原因应该就在Integer.valueOf(int i)这个方法里面了。好,继续跟踪,看看Integer.valueOf(int i)做了什么见不得人的事.

 

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);
    }


    看到这源码,相信大家都OK了,如果-128<=i<=127就从IntegerCache.cache[]数组中获得Integer对象,如果不是就直接new,那么再看看IntegerCache.cache[]数组是什么。继续追踪.......

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);
	}
    }

       追踪到这,终于松了口气了,原来加载IntegerCache类是就初始化了Integer类型的cache[]数组,并将数值位于-128到127之间的Integer对象保存到数组中。如果Integer.valueOf(int i)中的i如果位于该范围,就直接把数组内对应的对象引用值返回,所以Integer c=100,d=100;c==d是成立的,因为他们都指向同一个对象,而对于Integer e=1000,f=1000;e==f不成立,因为他们都不在范围内,直接new了。
        对于Short,Long都是一样,Double就不一样了,呵呵,大家可以查看源码,这样更清晰原因。

 
 
 
 
 
 
 
 
 

 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值