转载自:
http://blog.csdn.net/ma451152002/article/details/9076793
http://blog.csdn.net/snail_rao/article/details/7639194
jdk的不可变类:
primitive变量: boolean,byte, char, double ,float, integer, long, shortjdk的不可变类:jdk的java.lang包中 Boolean, Byte, Character, Double, Float, Integer, Long, Short, String.
其实Integer与int类型的赋值与比较最关键的一点就是:这两个变量的类型不同。Integer是引用类型,int是原生数据类型。
我们分四种情况来讨论:
1) Integer与int类型的赋值
a.把Integer类型赋值给int类型。此时,int类型变量的值会自动装箱成Integer类型,然后赋给Integer类型的引用,这里底层就是通过调用valueOf()这个方法来实现所谓的装箱的。
b.把int类型赋值给Integer类型。此时,Integer类型变量的值会自动拆箱成int类型,然后赋给int类型的变量,这里底层则是通过调用intValue()方法来实现所谓的拆箱的。
2) Integer与int类型的比较
这里就无所谓是谁与谁比较了,Integer == int与int == Integer的效果是一样的,都会把Integer类型变量拆箱成int类型,然后进行比较,相等则返回true,否则返回false。同样,拆箱调用的还是intValue()方法。
3) Integer之间的比较
这个就相对简单了,直接把两个引用的值(即是存储目标数据的那个地址)进行比较就行了,不用再拆箱、装箱什么的。
4) int之间的比较
这个也一样,直接把两个变量的值进行比较。
值得注意的是:对Integer对象,JVM会自动缓存-128~127范围内的值,所以所有在这个范围内的值相等的Integer对象都会共用一块内存,而不会开辟多个;超出这个范围内的值对应的Integer对象有多少个就开辟多少个内存。底层代码如下:
- public static Integer valueOf(int i) {
- assert IntegerCache.high >= 127;
- if (i >= IntegerCache.low && i <= IntegerCache.high)
- return IntegerCache.cache[i + (-IntegerCache.low)];
- return new Integer(i);
- }
测试代码如下:
- public class IntegerAndIntTest
- {
- public static void main(String[] args) throws Exception
- {
- Integer a = 127, b = 128;
- int c = 128;
- //自动装箱,这里会调用Integer中的valueOf方法把c装箱成Integer类型
- a = c;
- //这里比较的是两个对象的地址,显然不等
- System.out.println(a == b);
- //这里会调用Integer的intValue方法获得Integer对象a指向的栈地址中存的值再与c进行值比较,
- //而不是把c装箱成Integer类型进行地址比较
- System.out.println(a == c);
- //同上,也是获得a指向的栈地址中存的值
- System.out.println(c == a);
- /**
- * 总结:只有在赋值(=)的时候才会出现装箱和拆箱两种情况,
- * 在比较(==)的时候只会出现一种情况,那就是拆箱,而不会出现装箱的情况
- */
- System.out.println("----------------------------------");
- Integer i1 = 127;
- Integer i2 = 127;
- System.err.println(i1 == i2);
- i1 = 128;
- i2 = 128;
- System.err.println(i1 == i2);
- /**
- * 总结:JVM会自动缓存-128~127范围内的值,所以所有在这个范围内的值相等的Integer对象都会共用一块内存,而不会开辟多个;
- * 超出这个范围内的值对应的Integer对象有多少个就开辟多少个内存,这样做是为了节省内存消耗。
- */
- }
- }
反编译结果:具体看第2、9、22、27、38、72、92、116、123、149、157等行,这几行涉及到装箱、拆箱。
- public static void main(java.lang.String[]) throws java.lang.Exception;
- flags: ACC_PUBLIC, ACC_STATIC
- Exceptions:
- throws java.lang.Exception
- Code:
- stack=3, locals=7, args_size=1
- 0: bipush 127
- 2: invokestatic #19 // Method java/lang/Integer.valueO
- f:(I)Ljava/lang/Integer;
- 5: astore_1
- 6: sipush 128
- 9: invokestatic #19 // Method java/lang/Integer.valueO
- f:(I)Ljava/lang/Integer;
- 12: astore_2
- 13: sipush 128
- 16: istore_3
- 17: bipush 127
- 19: istore 4
- 21: iload_3
- 22: invokestatic #19 // Method java/lang/Integer.valueO
- f:(I)Ljava/lang/Integer;
- 25: astore_1
- 26: aload_1
- 27: invokevirtual #25 // Method java/lang/Integer.intVal
- ue:()I
- 30: istore 4
- 32: getstatic #29 // Field java/lang/System.out:Ljav
- a/io/PrintStream;
- 35: iload 4
- 37: aload_1
- 38: invokevirtual #25 // Method java/lang/Integer.intVal
- ue:()I
- 41: if_icmpne 48
- 44: iconst_1
- 45: goto 49
- 48: iconst_0
- 49: invokevirtual #35 // Method java/io/PrintStream.prin
- tln:(Z)V
- 52: getstatic #29 // Field java/lang/System.out:Ljav
- a/io/PrintStream;
- 55: aload_1
- 56: aload_2
- 57: if_acmpne 64
- 60: iconst_1
- 61: goto 65
- 64: iconst_0
- 65: invokevirtual #35 // Method java/io/PrintStream.prin
- tln:(Z)V
- 68: getstatic #29 // Field java/lang/System.out:Ljav
- a/io/PrintStream;
- 71: aload_1
- 72: invokevirtual #25 // Method java/lang/Integer.intVal
- ue:()I
- 75: iload_3
- 76: if_icmpne 83
- 79: iconst_1
- 80: goto 84
- 83: iconst_0
- 84: invokevirtual #35 // Method java/io/PrintStream.prin
- tln:(Z)V
- 87: getstatic #29 // Field java/lang/System.out:Ljav
- a/io/PrintStream;
- 90: iload_3
- 91: aload_1
- 92: invokevirtual #25 // Method java/lang/Integer.intVal
- ue:()I
- 95: if_icmpne 102
- 98: iconst_1
- 99: goto 103
- 102: iconst_0
- 103: invokevirtual #35 // Method java/io/PrintStream.prin
- tln:(Z)V
- 106: getstatic #29 // Field java/lang/System.out:Ljav
- a/io/PrintStream;
- 109: ldc #41 // String ------------------------
- ----------
- 111: invokevirtual #43 // Method java/io/PrintStream.prin
- tln:(Ljava/lang/String;)V
- 114: bipush 127
- 116: invokestatic #19 // Method java/lang/Integer.valueO
- f:(I)Ljava/lang/Integer;
- 119: astore 5
- 121: bipush 127
- 123: invokestatic #19 // Method java/lang/Integer.valueO
- f:(I)Ljava/lang/Integer;
- 126: astore 6
- 128: getstatic #46 // Field java/lang/System.err:Ljav
- a/io/PrintStream;
- 131: aload 5
- 133: aload 6
- 135: if_acmpne 142
- 138: iconst_1
- 139: goto 143
- 142: iconst_0
- 143: invokevirtual #35 // Method java/io/PrintStream.prin
- tln:(Z)V
- 146: sipush 128
- 149: invokestatic #19 // Method java/lang/Integer.valueO
- f:(I)Ljava/lang/Integer;
- 152: astore 5
- 154: sipush 128
- 157: invokestatic #19 // Method java/lang/Integer.valueO
- f:(I)Ljava/lang/Integer;
- 160: astore 6
- 162: getstatic #46 // Field java/lang/System.err:Ljav
- a/io/PrintStream;
- 165: aload 5
- 167: aload 6
- 169: if_acmpne 176
- 172: iconst_1
- 173: goto 177
- 176: iconst_0
- 177: invokevirtual #35 // Method java/io/PrintStream.prin
- tln:(Z)V
- 180: return
Integer的自动拆装箱的陷阱(整型数-128到127的值比较问题):
1、先看下面的例子:
- package integerdemo;
- public class IntegerDemo {
- public static void main(String[] args) {
- //-128--127之间
- Integer i1 = 100;
- Integer i2 = 100;
- if( i1 == i2){
- System.out.println("i1 == i2");
- }else{
- System.out.println("i1 != i2 ");
- }
- //大于127
- Integer i3 = 200;
- Integer i4 = 200;
- if( i3 == i4){
- System.out.println("i3 == i4");
- }else{
- System.out.println("i3 != i4 ");
- }
- }
- }
运行结果:
- run:
- i1 == i2
- i3 != i4
- 成功构建 (总时间: 1 秒)
以上是靠整型数的自动拆装箱实现的,而两者的结果却不相同。
原因在于,在进行自动拆装箱时,编译器会使用Integer.valueof()来创建Integer实例。
2、以下是Integer.valueof()的源代码:
- public static Integer valueOf(int i) {
- assert IntegerCache.high >= 127;
- if (i >= IntegerCache.low && i <= IntegerCache.high)
- return IntegerCache.cache[i + (-IntegerCache.low)];
- return new Integer(i);
- }
简单地解释这段代码,就是如果传入的int在IntegerCache.low和IntegerCache.high之间,那就尝试看前面的缓存中有没有打过包的相同的值,如果有就直接返回,否则就创建一个Integer实例。IntegerCache.low 默认是-128;IntegerCache.high默认是127.
注:如果要比较两个对象的内容是否相同,尽量不使用== 或者!= 来比较,可以使用equal()来实现。