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). 这是最快的存储区,因为它位于不同于其他存储区的地方——处理器内部.但是寄存器的数量极其有限,所以寄存器由编译器根据 ...
随机推荐
- grep 小技巧
转自:http://www.cnblogs.com/itech/archive/2012/10/18/2729944.html 1) grep命令加- E参数,这一扩展允许使用扩展模式匹配.例如,要抽 ...
- 第三章 k8s cluster环境创建
1 用如下方法安装指定版本的docker,但是我的环境会报错 # 安装rpm apt install rpm # 下载 RPM 包, docker 版本 wget https://download. ...
- 【学习笔记】FFT
1.内容 由于noble_太懒 不想写了 非常好的博客: https://www.cnblogs.com/rvalue/p/7351400.html http://www.cnblogs.com/ca ...
- JavaScript中的可枚举属性与不可枚举属性
在JavaScript中,对象的属性分为可枚举和不可枚举之分,它们是由属性的enumerable值决定的.可枚举性决定了这个属性能否被for…in查找遍历到. 一.怎么判断属性是否可枚举 js中基本包 ...
- iframe有哪些缺点?
iframe会阻塞主页面的Onload事件: iframe和主页面共享连接池,而浏览器对相同域的连接有限制,所以会影响页面的并行加载.使用iframe之前需要考虑这两个缺点.如果需要使用ifram ...
- 接口测试基础operation
Jmeter接口测试 一般分五个步骤: (1)添加线程组 (2)添加http请求 (3)在http请求中写入接入url.路径.请求方式和参数 (4)添加查看结果树 (5)调用接口.查看返回值
- CentOS7.6安装稳定版Nginx
官网地址:http://nginx.org/en/linux_packages.html#RHEL-CentOS 需先安装依赖:sudo yum install -y yum-utils 安装开始: ...
- Python基础学习九 数据库备份
class BakDb(object): def __init__(self,ip,username,passwd,port=3306,path=r'C:\Users\BJQT\Desktop\dat ...
- hbase安装与配置-分布式
HBASE安装与配置 备注: 1:本文在hadoop的完全分布式基础上部署hbase 2:本文使用的是小博主自己搭建的zookpeer服务,未使用hbase本身的zookpeer服务 本文内容在以下前 ...
- (转) iphone开发资源汇总
如何用Facebook graphic api上传视频: http://developers.facebook.com/blog/post/532/ Keychain保存数据封装: https://g ...