我们先看一个关于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\t" + (i1 == i2));
System.out.println("i1=i2+i3\t" + (i1 == i2 + i3));
System.out.println("i4=i5\t" + (i4 == i5));
System.out.println("i4=i5+i6\t" + (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\t" + (i1 == i2));
System.out.println("i1=i2+i3\t" + (i1 == i2 + i3));
System.out.println("i4=i5\t" + (i4 == i5));
System.out.println("i4=i5+i6\t" + (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\t
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\t
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\t
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\t
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的范围,所以都得重新初始化对象

java中Integer常量池的更多相关文章

  1. 【Java_基础】java中的常量池

    1.java常量池的介绍 java中的常量池,通常指的是运行时常量池,它是方法区的一部分,一个jvm实例只有一个运行常量池,各线程间共享该运行常量池. java常量池简介:java常量池中保存了一份在 ...

  2. Java中的常量池

    JVM中有: Class文件常量池.运行时常量池.全局字符串常量池.基本类型包装类对象 常量池 Class文件常量池: class文件是一组以字节为单位的二进制数据流,在java代码的编译期间,编写的 ...

  3. Java的Integer常量池和String常量池

    1.Integer的常量池 看下面一段代码: package cn.qlq.test; public class ArrayTest { public static void main(String[ ...

  4. Java中的常量池(字符串常量池、class常量池和运行时常量池)

    转载. https://blog.csdn.net/zm13007310400/article/details/77534349 简介: 这几天在看Java虚拟机方面的知识时,看到了有几种不同常量池的 ...

  5. 19、java内存分配 常量池详解

    在class文件中,“常量池”是最复杂也最值得关注的内容. Java是一种动态连接的语言,常量池的作用非常重要,常量池中除了包含代码中所定义的各种基本类型(如int.long等等)和对象型(如Stri ...

  6. 【万字图文-原创】 | 学会Java中的线程池,这一篇也许就够了!

    碎碎念 关于JDK源码相关的文章这已经是第四篇了,原创不易,粉丝从几十人到昨天的666人,真的很感谢之前帮我转发文章的一些朋友们. 从16年开始写技术文章,到现在博客园已经发表了222篇文章,大多数都 ...

  7. Java字面常量与常量池

    Java中的字面常量(区别于final创建的有名常量)通常会保存在常量池中,常量池可以理解为像堆一样的内存区域.但是常量池有一个特性就是,如果常量池中已存在该常量将不会再次为该常量开辟内存 还是看个程 ...

  8. 第46节:Java当中的常量池

    Java当中的常量池 在Java虚拟机jvm中,内存分布为:虚拟机堆,程序计数器,本地方法栈,虚拟机栈,方法区. 程序计数器是jvm执行程序的流水线,是用来存放一些指令的,本地方法栈是jvm操作系统方 ...

  9. Java堆/栈/常量池以及String的详细详解(转)------经典易懂系统

    一:在JAVA中,有六个不同的地方可以存储数据: 1. 寄存器(register). 这是最快的存储区,因为它位于不同于其他存储区的地方——处理器内部.但是寄存器的数量极其有限,所以寄存器由编译器根据 ...

随机推荐

  1. video2gift环境安装(Theano等)

    pip install Theano http://deeplearning.net/software/theano/install_centos6.html pip install moviepy ...

  2. 我编辑的JAVA日历程序

    class calendar { public static void main(String[]args) { int yearIn ; yearIn = Integer.parseInt(args ...

  3. django之部署

    布署 从uwsgi.nginx.静态文件三个方面处理 服务器介绍 服务器:私有服务器.公有服务器 私有服务器:公司自己购买.自己维护,只布署自己的应用,可供公司内部或外网访问 公有服务器:集成好运营环 ...

  4. TCP超时与重传机制

    TCP超时与重传机制    TCP协议是一种面向连接的可靠的传输层协议,它保证了数据的可靠传输,对于一些出错,超时丢包等问题TCP设计的超时与重传机制.其基本原理:在发送一个数据之后,就开启一个定时器 ...

  5. halcon的长度和角度测量

    halcon代码: 1: *读取并截取图片 2: dev_close_window() 3: read_image (Image, 'D:/MyFile/halcon/长度和角度测量/图.png') ...

  6. oracle对表常用的操作

    最近业务需要给表添加索引,因为数据量很大时,查询效率很低:老大建议使用索引: 之前总结的时候将索引没有记录,当然啦,也怪笔者基础薄弱,不管了,慢慢进步嘛,好了进入正题吧! 首先准备工作,先建两个临时表 ...

  7. 修改SecureCRT终端的Home和End功能键。

    SecureCRT真是个不错的ssh客户端工具,但在使用时发现跟自己的一些使用习惯不符合,例如home.end.pageup.pagedown和delete等键. 默认情况下一些按键的功能如下: pa ...

  8. Synchronized块同步变量的误区

    我们可以通过synchronized块来同步特定的静态或非静态方法.要想实现这种需求必须为这些特性的方法定义一个类变量,然后将这些方法的代码用synchronized块括起来,并将这个类变量作为参数传 ...

  9. Cookie&Session会话跟踪技术

    今日内容学习目标 可以响应给浏览器Cookie信息[response.addCookie()] 可以接受浏览器Cookie信息[request.getCookies()] [创建cookie,设置pa ...

  10. iOS开发基础控件--UIButton

    01 //这里创建一个圆角矩形的按钮 02     UIButton *button1 = [UIButton buttonWithType:UIButtonTypeRoundedRect]; 03 ...