java不得不说的秘密-Integer关于等等的秘密

java不得不说的秘密-Integer关于等等的秘密废话不 多少先问下 下面 6 个 判断输出结果是什么 Integer a 127 Integer b 127 Integer c new Integer 127 i

大家好,欢迎来到IT知识分享网。

废话不‬多少先问下,下面6个==判断输出结果是什么:

 Integer a = 127; Integer b = 127; Integer c = new Integer(127); int aInt = 127; Integer a1 = 200; Integer a11 = 200; int aInt1 = 200; System.out.println("1、Integer a = 127 和 Integer b = 127 ==结果: " + (a == b)); System.out.println("2、Integer a = 127 和 Integer c = new Integer(127) ==结果: " + (a == c)); System.out.println("3、Integer a = 127 和 int aInt = 127 ==结果:" + (a == aInt)); System.out.println("4、Integer c = new Integer(127) 和 int aInt = 127 ==结果:" + (c == aInt)); System.out.println("5、Integer a1 = 200 和 Integer a1 = 200 ==结果:"+ (a1 == a11)); System.out.println("6、Integer a1 = 200 和 int aInt1 = 200 ==结果:" + (a1 == aInt1));

输出的结果是:

1、Integer a = 127 和 Integer b = 127 ==结果: true 2、Integer a = 127 和 Integer c = new Integer(127) ==结果: false 3、Integer a = 127 和 int aInt = 127 ==结果:true 4、Integer c = new Integer(127) 和 int aInt = 127 ==结果:true 5、Integer a1 = 200 和 Integer a1 = 200 ==结果:false 6、Integer a1 = 200 和 int aInt1 = 200 ==结果:true

通过结果可以发现:
问题1: 1和5是类似的等等,只是值不一样,为什么一个true一个false?
问题2: 1和2是不同定义的Intenger,值都是一样的,为什么一个true一个false?
问题3: 3、4和6结果一致,为什么Intenger和int的等等为true?

关于以上问题,暂时不公布答案,再来一波灵魂拷问:
自动装箱和拆箱是怎么实现的?
答案在: java不得不说的秘密-自动装箱拆箱

那么接下来我们先看 == 字节码做了什么?
第一、先看比较1和5中的定义和比较做了什么
代码:

package org.test; public class Test { Integer a = 127; Integer b = 127; boolean f = a == b; Integer a1 = 200; Integer a11 = 200; boolean f1 = a1 == a11; }

字节码片段:

 public org.test.Test(); descriptor: ()V flags: ACC_PUBLIC Code: stack=3, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: aload_0 5: bipush 127 7: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; 10: putfield #3 // Field a:Ljava/lang/Integer; 13: aload_0 14: bipush 127 16: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; 19: putfield #4 // Field b:Ljava/lang/Integer; 22: aload_0 23: aload_0 24: getfield #3 // Field a:Ljava/lang/Integer; 27: aload_0 28: getfield #4 // Field b:Ljava/lang/Integer; 31: if_acmpne 38 34: iconst_1 35: goto 39 38: iconst_0 39: putfield #5 // Field f:Z 42: aload_0 43: sipush 200 46: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; 49: putfield #6 // Field a1:Ljava/lang/Integer; 52: aload_0 53: sipush 200 56: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; 59: putfield #7 // Field a11:Ljava/lang/Integer; 62: aload_0 63: aload_0 64: getfield #6 // Field a1:Ljava/lang/Integer; 67: aload_0 68: getfield #7 // Field a11:Ljava/lang/Integer; 71: if_acmpne 78 74: iconst_1 75: goto 79 78: iconst_0 79: putfield #8 // Field f1:Z 82: return

先找f发现:

39: putfield #5 // Field f:Z

再找f1发现:

 79: putfield #8 // Field f1:Z

在向上找发现了自动装箱的操作Integer.valueOf,其他都没有特殊之处了。

那么有什么样的秘密,导致了问题1的出现呢?

接下来我们借助

System.identityHashCode(Object o);

该方法不管对象有没有重写hashCode方法,都只会调用Object的hashCode方法。

看下面程序的结果:

package org.test; public class Test { public static void main(String[] args) { Integer a = 127; Integer b = 127; boolean f = a == b; Integer a1 = 200; Integer a11 = 200; boolean f1 = a1 == a11; System.out.println(System.identityHashCode(a)); System.out.println(System.identityHashCode(b)); System.out.println(System.identityHashCode(a1)); System.out.println(System.identityHashCode(a11)); } }

结果:

   

可以发现127这个数据经过Integer.valueOf函数hashCode一致,而200这个数据确不一致。
那么什么原因导致
Integer.valueOf在不同的数值上表现的不一致呢?

见证秘密的时刻到了,来看Integer.valueOf这个方法内容是什么

 / * Returns an {@code Integer} instance representing the specified * {@code int} value. If a new {@code Integer} instance is not * required, this method should generally be used in preference to * the constructor {@link #Integer(int)}, as this method is likely * to yield significantly better space and time performance by * caching frequently requested values. * * This method will always cache values in the range -128 to 127, * inclusive, and may cache other values outside of this range. * * @param i an {@code int} value. * @return an {@code Integer} instance representing {@code i}. * @since 1.5 */ public static Integer valueOf(int i) { if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); }

通过代码,我们已经清楚了这个秘密。即:
Integer.valueOf方法总会缓存-128到127之间的值

问题1所以有了问题2,关于问题2应该符合我们认知的Java语法。
毕竟存在 new 操作,这两个对象本用==比较本就该不一样。

还有最后一个疑问,问题3。来,先上字节码。
代码如下:

package org.test; public class Test { Integer a = 127; Integer c = new Integer(127); int aInt = 127; boolean f = a == aInt; boolean f1 = aInt == a; boolean f2 = c == aInt; }

字节码片段如下:

public org.test.Test(); descriptor: ()V flags: ACC_PUBLIC Code: stack=4, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: aload_0 5: bipush 127 7: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; 10: putfield #3 // Field a:Ljava/lang/Integer; 13: aload_0 14: new #4 // class java/lang/Integer 17: dup 18: bipush 127 20: invokespecial #5 // Method java/lang/Integer."<init>":(I)V 23: putfield #6 // Field c:Ljava/lang/Integer; 26: aload_0 27: bipush 127 29: putfield #7 // Field aInt:I 32: aload_0 33: aload_0 34: getfield #3 // Field a:Ljava/lang/Integer; 37: invokevirtual #8 // Method java/lang/Integer.intValue:()I 40: aload_0 41: getfield #7 // Field aInt:I 44: if_icmpne 51 47: iconst_1 48: goto 52 51: iconst_0 52: putfield #9 // Field f:Z 55: aload_0 56: aload_0 57: getfield #7 // Field aInt:I 60: aload_0 61: getfield #3 // Field a:Ljava/lang/Integer; 64: invokevirtual #8 // Method java/lang/Integer.intValue:()I 67: if_icmpne 74 70: iconst_1 71: goto 75 74: iconst_0 75: putfield #10 // Field f1:Z 78: aload_0 79: aload_0 80: getfield #6 // Field c:Ljava/lang/Integer; 83: invokevirtual #8 // Method java/lang/Integer.intValue:()I 86: aload_0 87: getfield #7 // Field aInt:I 90: if_icmpne 97 93: iconst_1 94: goto 98 97: iconst_0 98: putfield #11 // Field f2:Z 101: return LineNumberTable: line 3: 0 line 4: 4 line 5: 13 line 6: 26 line 8: 32 line 9: 55 line 10: 78

通过字节码我们发现当int和Integer进行==Integer.intValue会对Integer进行拆箱,而该函数如下:

 / * Returns the value of this {@code Integer} as an * {@code int}. */ public int intValue() { return value; }

总结:
第一、 Integer.valueOf方法总会缓存-128到127之间的值,超过该返回会产生新的Integer对象。所以 -128到127之间的值==为true,超过范围为false
第二、 new Integer(value) 总是产生对象,不会有缓存处理。为了让Java 语法总是保持一致。所以 ==永远为false
第三、 Integer和int比较,编译为字节码后Integer对象会调用intValue在和int进行==操作,所以为true

看完,是不是恍然大悟。

留点疑问,评论区见。
1、Integer 类型的对象用什么比较是否值相等?
2、其他7个包装类是否也会有装箱的缓存值?
3、包装类的equals方法是否可以入参基本数据类型?

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/92837.html

(0)
上一篇 2024-10-24 10:15
下一篇 2024-10-24 11:26

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

关注微信