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\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常量池的更多相关文章
- 【Java_基础】java中的常量池
1.java常量池的介绍 java中的常量池,通常指的是运行时常量池,它是方法区的一部分,一个jvm实例只有一个运行常量池,各线程间共享该运行常量池. java常量池简介:java常量池中保存了一份在 ...
- Java中的常量池
JVM中有: Class文件常量池.运行时常量池.全局字符串常量池.基本类型包装类对象 常量池 Class文件常量池: class文件是一组以字节为单位的二进制数据流,在java代码的编译期间,编写的 ...
- Java的Integer常量池和String常量池
1.Integer的常量池 看下面一段代码: package cn.qlq.test; public class ArrayTest { public static void main(String[ ...
- Java中的常量池(字符串常量池、class常量池和运行时常量池)
转载. https://blog.csdn.net/zm13007310400/article/details/77534349 简介: 这几天在看Java虚拟机方面的知识时,看到了有几种不同常量池的 ...
- 19、java内存分配 常量池详解
在class文件中,“常量池”是最复杂也最值得关注的内容. Java是一种动态连接的语言,常量池的作用非常重要,常量池中除了包含代码中所定义的各种基本类型(如int.long等等)和对象型(如Stri ...
- 【万字图文-原创】 | 学会Java中的线程池,这一篇也许就够了!
碎碎念 关于JDK源码相关的文章这已经是第四篇了,原创不易,粉丝从几十人到昨天的666人,真的很感谢之前帮我转发文章的一些朋友们. 从16年开始写技术文章,到现在博客园已经发表了222篇文章,大多数都 ...
- Java字面常量与常量池
Java中的字面常量(区别于final创建的有名常量)通常会保存在常量池中,常量池可以理解为像堆一样的内存区域.但是常量池有一个特性就是,如果常量池中已存在该常量将不会再次为该常量开辟内存 还是看个程 ...
- 第46节:Java当中的常量池
Java当中的常量池 在Java虚拟机jvm中,内存分布为:虚拟机堆,程序计数器,本地方法栈,虚拟机栈,方法区. 程序计数器是jvm执行程序的流水线,是用来存放一些指令的,本地方法栈是jvm操作系统方 ...
- Java堆/栈/常量池以及String的详细详解(转)------经典易懂系统
一:在JAVA中,有六个不同的地方可以存储数据: 1. 寄存器(register). 这是最快的存储区,因为它位于不同于其他存储区的地方——处理器内部.但是寄存器的数量极其有限,所以寄存器由编译器根据 ...
随机推荐
- http 和 https 区别?
1. HTTP 的URL 以http:// 开头,而HTTPS 的URL 以https:// 开头2. HTTP 是不安全的,而 HTTPS 是安全的3. HTTP 标准端口是80 ,而 HTTPS ...
- 卷积神经网络之AlexNet网络模型学习
ImageNet Classification with Deep Convolutional Neural Networks 论文理解 在ImageNet LSVRC-2010上首次使用大型深度卷 ...
- Druid.io系列(四):索引过程分析
原文链接: https://blog.csdn.net/njpjsoftdev/article/details/52956083 Druid底层不保存原始数据,而是借鉴了Apache Lucene.A ...
- zabbix server的Discover功能,实现zabbix agent 大批量的自动添加,并链接到指定的模版(3)
一.需求 zabbix 服务器可以手动加入zabbix-agent客户端,对于少量的机器,这没有什么.但到了线上,我们有大量的服务器需要监控时,如果再一个个的手动加的话,工作量势必会增加很多.这时,z ...
- 浅谈OPP
了解Java或C#等面向对象编程语言的的程序员比较熟悉类和对象以及OOP. 一谈起OOP,就会想起教科书式的OOP概念:封装.继承.多态.粗浅的解释封装就是对数据进行隐藏:继承就是子类继承父类(cla ...
- c#中的序列化
1.对象的序列化 NET支持对象序列化有以下几种方式:二进制序列化:对象序列化之后是二进制形式的,通过BinaryFormatter类来实现的,这个类位于System.Runtime.Serializ ...
- PHP 数据集循环
循环 $rs = $bbs->query("select top 10 * from tt"); while($row = $rs->fetch()) { //prin ...
- 2.Hadoop集群搭建之Hadoop(包含HDFS和Yarn)安装
前期准备 下载JDK 6.0以上版本 下载Hadoop 2.4.1 1. 安装JDK 因为Hadoop是Java开发的,所以需要安装JDK,建议JDK 6.0以上. 解压JDK tar -zxvf J ...
- ElasticSearch中如何让query should等同于filter should
bool query must The clause (query) must appear in matching documents. should The clause (query) shou ...
- failed to open stream: No such file or directory 报错解决方法
1.首先检查是否是文件名错误(比如有空格):是否因为路径不完整(比如缺少http://,或者缺少文件扩展名.doc等): 2.若是在本地中文名文件打开报错,我就是因为编码不一致导致: Windows中 ...