文档章节

Integer与int解惑

反经
 反经
发布于 2017/01/17 22:18
字数 1202
阅读 7
收藏 1

jdk1.5引入了自动装箱(autoboxing)与自动拆箱(unboxing),这方便了集合类以及一些方法的调用,同时也使初学者对其感到非常之困惑。在此,我们来揭开其神秘的面纱。

首先,需要厘清一些概念:
1、Integer是一个类,用Integer声明一个变量其是一个对象类型(或者说引用类型);int是基本类型,用int声明的变量是非对象类型,即不能在其上调用方法。
2、“==”作用于对象上的时候,其比较的是对象的引用本身的值(或者说对象的地址更容易理解),而作用于基本类型的时候比较的就是基本类型的值。
接下来看一段代码:

public class Test {
	public static void main(String[] args) {
		Integer i1 = 2;
		int i2 = 2;
		System.out.println(i1 == i2);
	}
}

在这段代码中有两个令人困惑的问题,首先是将一个基本类型的值赋值给对象的引用,即Integer i1 =2;其次是拿一个对象类型和一个基本类型比较。按理说这两种做法肯定都是有问题的,在jdk1.4(若使用的jdk版本是1.5或之后的版本中,可以使用javac -source 1.4 Test.java来编译)上,确实如此,第一个问题在编译时会报“不兼容的类型”错误,第二个问题会报“运算符 == 不能应用于 java.lang.Integer,int”的错误。
但是jdk1.5引入的自动装箱和自动拆箱,那么,必然要将其中的一种类型转换成另一种类型,究竟是将Integer对象i1转换成int基本类型呢?还是将int基本类型的i2转换成Integer对象?通过javap -c Test反编译Test.class文件就知道答案了:

public static void main(java.lang.String[]);
Code:
0:   iconst_2
1:   invokestatic    #2; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
4:   astore_1
5:   iconst_2
6:   istore_2
7:   getstatic       #3; //Field java/lang/System.out:Ljava/io/PrintStream;
10:  aload_1
11:  invokevirtual   #4; //Method java/lang/Integer.intValue:()I
14:  iload_2
15:  if_icmpne       22
18:  iconst_1
19:  goto23
22:  iconst_0
23:  invokevirtual   #5; //Method java/io/PrintStream.println:(Z)V
26:  return
}

其中,[0-4]是Integer i1 = 2的实现,我们发现,编译的字节码里调用了Integer.valueOf方法,因此Integer i1 = 2编译后就等同于Integer i1 = Integer.valueOf(2);[5,6]是int i2 = 2的实现;[7,23]是System.out.println(i1 == i2)的实现,也容易看到,里面调用了Integer.intValue()方法。因此,这个i1 == i2这两个不同类型的变量比较,在编译的时候,编译器是将其转换成相同的类型进行比较的,即将对象类型转换成基本类型,System.out.println(i1 == i2)就等同于System.out.println(i1.intValue() == i2),前面说了,“==”作用于基本类型的时候比较的就是基本类型的值,两个值都是2,所以结果是true。
另外一个令人困惑的例子就是:

public class Test {
	public static void main(String[] args) {
		Integer i1 = 127;
		Integer i2 = 127;
		System.out.println(i1 == i2);
		Integer i3 = 128;
		Integer i4 = 128;
		System.out.println(i3 == i4);
	}
}

运行后发现,i1==i2的结果为true,i3==i4的结果为false?这令不知原因的人头疼不已。在前面一个例子里我们已经说过,诸如Integer i1 = 127,在编译后就等同于Integer i1 = Integer.valueOf(127),既然是调用一个方法来获得对象,那么就有必要对valueOf方法一探究竟了。我们看下源码:

public static Integer valueOf(inti) {
	final int offset = 128;
	if(i <= -128 && i < code>127) { // must cache
		return IntegerCache.cache[i + offset];
	}
	return new Integer(i);
}

到此应该恍然大悟了,IntegerCache缓存了[-128,127]之间的Integer对象,如果valueOf的参数i处于这之间,就返回缓存的对象。否则就new一个新的Integer。前面已经说过,“==”作用于对象上的时候,其比较的是对象的地址,例子中的i1和i2都是从缓存中拿的,当然是同一个对象,i3和i4都是通过new Integer获得的,当然不是同一个对象了。
类似地,java.lang.Long,java.lang.Short分别缓存了[-128,127]之间的Long和Short对象,java.lang.Byte缓存了所有的对象,java.lang.Character缓存了[0,127]之间的Character对象。java缓存这些对象是为了性能优化,既然我们已经知道其缓存了这么些对象,在需要new Integer/Long/…的地方,可改用Integer/Long/Short…#valueOf方法。
但是:
使用Oracle/Sun JDK 6,在server模式下,使用-XX:AutoBoxCacheMax=NNN参数即可将Integer的自动缓存区间设置为[-128,NNN]。注意区间的下界固定在-128不可配置。
在client模式下该参数无效。这个参数是server模式专有的,在c2_globals.hpp中声明,默认值是128;不过这个默认值在默认条件下不起作用,要手动设置它的值或者是开启-XX:+AggressiveOpts参数才起作用。


更多信息http://rednaxelafx.iteye.com/blog/680746
 

 

本文转载自:

反经
粉丝 36
博文 172
码字总数 43569
作品 0
广州
程序员
私信 提问
关于JAVA中Integer的==运算!

i == j 为false我知道,但为什么 200 == i会为true呢? Integer不是只cache[-128 ~ 127]的数字吗 求解惑

林小宝
2014/03/21
1K
2
Java集合--HashMap解惑

3 Map 昨晚去了鸟巢,膜拜了5位40多岁的大爷们。算上这次,已是第三回了,每一次都有不同的感受、体验。期待,下一次的相遇。 说正题前,先附一张昨晚演唱会的图片! 今天,笔者要介绍的是J...

贾博岩
2017/08/27
0
0
mybaits3.4 返回主键失败(Error getting generated key or setting result to parameter object)

在项目中进行新增后,根据返回主键在更新数据,但是使用mybaits的主键返回。直接报错了 1.第一种实现方式 ,有人说返回的是一个对象,所以设置keyProperty="对象.字段" 2.第二种实现方式 3....

安静的程序猿
2018/12/28
836
3
为何synchronized无法同步控制Integer等数字类型的对象

今天在学习synchronized同步时候,动手写了段代码来验证。但是却发现synchronized无法控制同步Integer等数字类型的数据,但使用普通类型对象却是正确的。还望各位大虾不吝赐教,帮忙解惑,谢...

找寻
2011/05/09
2.5K
13
java.lang.Integer

Integer的定义 public final class Integer extends Number implements Comparable Integer类在对象中包装了一个基本类型int的值。Integer类型的对象包含一个int类型的字段。 此外,该类提供...

zengxiantao1994
2017/10/08
0
0

没有更多内容

加载失败,请刷新页面

加载更多

OSChina 周二乱弹 —— 他只能用这个办法劝你注意身体了

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @-冰冰棒- :#今日歌曲推荐# Kodaline《High Hopes》 《High Hopes》- Kodaline 手机党少年们想听歌,请使劲儿戳(这里) @xiaoshiyue :仙女...

小小编辑
30分钟前
804
15
Spring Boot Actuator 整合 Prometheus

简介 Spring Boot 自带监控功能 Actuator,可以帮助实现对程序内部运行情况监控,比如监控状况、Bean加载情况、环境变量、日志信息、线程信息等。这一节结合 Prometheus 、Grafana 来更加直观...

程序员果果
39分钟前
10
0
Linux文件查找命令详解

对于文件查找,我们最好用的还是属于find命令了,在说find命令之前,先把另外几个查找命令介绍一下。 目录 0x01 查询命令介绍 0x02 find命令介绍 0x01 查询命令介绍 在介绍之前,首先先了解一...

无心的梦呓
39分钟前
7
0
快速掌握的测试用例优先级划分方法

怎么样的设计才能算测试用例 引自:IEEE Standard 610 (1990): A set of test inputs, execution conditions, and expected results developed for a particular objective, such as to exe......

测者陈磊
42分钟前
6
0
[mycat]Attribute value "roadNodeId,version" of type NMTOKEN must be a name token

不能逗号配两个字段的主键 primaryKey="roadNodeId,version" Caused by: io.mycat.config.util.ConfigException: org.xml.sax.SAXParseException; lineNumber: 7; columnNumber: 105; Attrib......

Danni3
48分钟前
6
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部