java中Integer常量池

    我们先看一个关于Integer的例子

public static void main(String[] args) {
		// TeODO Auto-generated method stu
        Integer i1 = 40;
        Integer i2 = 40;
        Integer i3 = 0;
        Integer i4 = new Integer(40);
        Integer i5 = new Integer(40);
        Integer i6 = new Integer(0);
        
        System.out.println("i1=i2	" + (i1 == i2));
        System.out.println("i1=i2+i3	" + (i1 == i2 + i3));
        System.out.println("i4=i5	" + (i4 == i5));
        System.out.println("i4=i5+i6	" + (i4 == i5 + i6));    
        
        System.out.println();     
	}
}

 结果:

i1=i2     true
i1=i2+i3  true
i4=i5  false
i4=i5+i6  true

 再看一个例子

public static void main(String[] args) {
	// TeODO Auto-generated method stu
        Integer i1 = 400;
        Integer i2 = 400;
        Integer i3 = 0;
        Integer i4 = new Integer(400);
        Integer i5 = new Integer(400);
        Integer i6 = new Integer(0);
        
        System.out.println("i1=i2	" + (i1 == i2));
        System.out.println("i1=i2+i3	" + (i1 == i2 + i3));
        System.out.println("i4=i5	" + (i4 == i5));
        System.out.println("i4=i5+i6	" + (i4 == i5 + i6));    
        
        System.out.println();     
	}
}

 结果

i1=i2     false
i1=i2+i3  true
i4=i5  false
i4=i5+i6  true

 比较上面两个例子,我们发现:两个例子代码几乎一样,就是值不一样,40和400的区别怎么会造成如此大的结果差别呢??

我们用上篇博客的方法,用javap看他们的反编译结果

public class com.study.main.Test extends java.lang.Object{
public com.study.main.Test();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return

public static void main(java.lang.String[]);
  Code:
   0:   sipush  400 //40时我们用cipush(下同)  cipush(char 类型)的值范围是-128——127,sipush(short 类型)的值范围是2^15——2^15-1,
3: invokestatic #2; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Int eger; 6: astore_1 7: sipush 400 10: invokestatic #2; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Int eger; 13: astore_2 14: iconst_0 15: invokestatic #2; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Int eger; 18: astore_3 19: new #3; //class java/lang/Integer 22: dup 23: sipush 400 26: invokespecial #4; //Method java/lang/Integer."<init>":(I)V 29: astore 4 31: new #3; //class java/lang/Integer 34: dup 35: sipush 400 38: invokespecial #4; //Method java/lang/Integer."<init>":(I)V 41: astore 5 43: new #3; //class java/lang/Integer 46: dup 47: iconst_0 48: invokespecial #4; //Method java/lang/Integer."<init>":(I)V 51: astore 6 53: getstatic #5; //Field java/lang/System.out:Ljava/io/PrintStream; 56: new #6; //class java/lang/StringBuilder 59: dup 60: invokespecial #7; //Method java/lang/StringBuilder."<init>":()V 63: ldc #8; //String i1=i2 65: invokevirtual #9; //Method java/lang/StringBuilder.append:(Ljava/lang/ String;)Ljava/lang/StringBuilder; 68: aload_1 69: aload_2 70: if_acmpne 77 73: iconst_1 74: goto 78 77: iconst_0 78: invokevirtual #10; //Method java/lang/StringBuilder.append:(Z)Ljava/la ng/StringBuilder; 81: invokevirtual #11; //Method java/lang/StringBuilder.toString:()Ljava/l ang/String; 84: invokevirtual #12; //Method java/io/PrintStream.println:(Ljava/lang/St ring;)V 87: getstatic #5; //Field java/lang/System.out:Ljava/io/PrintStream; 90: new #6; //class java/lang/StringBuilder 93: dup 94: invokespecial #7; //Method java/lang/StringBuilder."<init>":()V 97: ldc #13; //String i1=i2+i3 99: invokevirtual #9; //Method java/lang/StringBuilder.append:(Ljava/lang/ String;)Ljava/lang/StringBuilder; 102: aload_1 103: invokevirtual #14; //Method java/lang/Integer.intValue:()I 106: aload_2 107: invokevirtual #14; //Method java/lang/Integer.intValue:()I 110: aload_3 111: invokevirtual #14; //Method java/lang/Integer.intValue:()I 114: iadd 115: if_icmpne 122 118: iconst_1 119: goto 123 122: iconst_0 123: invokevirtual #10; //Method java/lang/StringBuilder.append:(Z)Ljava/la ng/StringBuilder; 126: invokevirtual #11; //Method java/lang/StringBuilder.toString:()Ljava/l ang/String; 129: invokevirtual #12; //Method java/io/PrintStream.println:(Ljava/lang/St ring;)V 132: getstatic #5; //Field java/lang/System.out:Ljava/io/PrintStream; 135: new #6; //class java/lang/StringBuilder 138: dup 139: invokespecial #7; //Method java/lang/StringBuilder."<init>":()V 142: ldc #15; //String i4=i5 144: invokevirtual #9; //Method java/lang/StringBuilder.append:(Ljava/lang/ String;)Ljava/lang/StringBuilder; 147: aload 4 149: aload 5 151: if_acmpne 158 154: iconst_1 155: goto 159 158: iconst_0 159: invokevirtual #10; //Method java/lang/StringBuilder.append:(Z)Ljava/la ng/StringBuilder; 162: invokevirtual #11; //Method java/lang/StringBuilder.toString:()Ljava/l ang/String; 165: invokevirtual #12; //Method java/io/PrintStream.println:(Ljava/lang/St ring;)V 168: getstatic #5; //Field java/lang/System.out:Ljava/io/PrintStream; 171: new #6; //class java/lang/StringBuilder 174: dup 175: invokespecial #7; //Method java/lang/StringBuilder."<init>":()V 178: ldc #16; //String i4=i5+i6 180: invokevirtual #9; //Method java/lang/StringBuilder.append:(Ljava/lang/ String;)Ljava/lang/StringBuilder; 183: aload 4 185: invokevirtual #14; //Method java/lang/Integer.intValue:()I 188: aload 5 190: invokevirtual #14; //Method java/lang/Integer.intValue:()I 193: aload 6 195: invokevirtual #14; //Method java/lang/Integer.intValue:()I 198: iadd 199: if_icmpne 206 202: iconst_1 203: goto 207 206: iconst_0 207: invokevirtual #10; //Method java/lang/StringBuilder.append:(Z)Ljava/la ng/StringBuilder; 210: invokevirtual #11; //Method java/lang/StringBuilder.toString:()Ljava/l ang/String; 213: invokevirtual #12; //Method java/io/PrintStream.println:(Ljava/lang/St ring;)V 216: getstatic #5; //Field java/lang/System.out:Ljava/io/PrintStream; 219: invokevirtual #17; //Method java/io/PrintStream.println:()V 222: return }

 比较后我们惊人的发现,两者其实没有什么区别

只有这里:

 0:   sipush  400 //40时我们用cipush(下同)  cipush(char 类型)的值范围是-128——127,sipush(short 类型)的值范围是2^15——2^15-1

我们看到第12行: 3:   invokestatic    #2; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Int

在Integer中是调用Integer.valueOf初始化对象的

Integer.valueOf函数

 public static Integer valueOf(int i) {
        if(i >= -128 && i <= IntegerCache.high)
            return IntegerCache.cache[i + 128];
        else
            return new Integer(i);
    }

IntegerCache

  private static class IntegerCache {
        static final int high;
        static final Integer cache[];

        static {
            final int low = -128;

            // high value may be configured by property
            int h = 127;
            if (integerCacheHighPropValue != null) {
                // Use Long.decode here to avoid invoking methods that
                // require Integer's autoboxing cache to be initialized
                int i = Long.decode(integerCacheHighPropValue).intValue();
                i = Math.max(i, 127);
                // Maximum array size is Integer.MAX_VALUE
                h = Math.min(i, Integer.MAX_VALUE - -low);
            }
            high = h;

            cache = new Integer[(high - low) + 1];
            int j = low;
            for(int k = 0; k < cache.length; k++)
                cache[k] = new Integer(j++);
        }

        private IntegerCache() {}
    }

通过研究发现:Integer.valueOf()中有个内部类IntegerCache(类似于一个常量数组,也叫对象池),它维护了一个Integer数组cache,长度为(128+127+1)=256;Integer类中还有一个Static Block(静态块),如上所示。

从这个静态块可以看出,Integer已经默认创建了数值【-128-127】的Integer缓存数据。所以使用Integer i1=40时,JVM会直接在该在对象池找到该值的引用。

也就是说这种方式声明一个Integer对象时,JVM首先会在Integer对象的缓存池中查找有木有值为40的对象,如果有直接返回该对象的引用;如果没有,则使用New keyword创建一个对象,并返回该对象的引用地址。因为Java中【==】比较的是两个对象是否是同一个引用(即比较内存地址),i2和i2都是引用的同一个对象,So i1==i2结果为”true“;而使用new方式创建的i4=new Integer(40)、i5=new Integer(40),虽然他们的值相等,但是每次都会重新Create新的Integer对象,不会被放入到对象池中,所以他们不是同一个引用,输出false。

  对于i1==i2+i3、i4==i5+i6结果为True,是因为,Java的数学计算是在内存栈里操作的,Java会对i5、i6进行拆箱操作,其实比较的是基本类型(40=40+0),他们的值相同,因此结果为True。

但是但为400时,这个时候已经超过了cache的范围,所以都得重新初始化对象

原文地址:https://www.cnblogs.com/fjsnail/p/3473791.html