概述
个人博客:www.letus179.com
Java是一个近乎纯洁的面向对象编程语言,但是为了编程的方便还是引入了基本数据类型,但是为了能够将这些基本数据类型当成对象操作,Java为每一个基本数据类型都引入了对应的包装类型(wrapper class),int的包装类就是Integer,从Java 5开始引入了自动装箱/拆箱机制,使得二者可以相互转换。
Java 为每个原始类型提供了包装类型:
- 原始类型:
boolean
,char
,byte
,short
,int
,long
,float
,double
- 包装类型:
Boolean
,Character
,Byte
,Short
,Integer
,Long
,Float
,Double
两个常见的面试例子
先看两个常见的例子,后面会针对例子加以分析。
例1
public static void main(String[] args) {
Integer a = new Integer(8);
Integer b = 8;
int c = 8;
System.out.println(a == b);
System.out.println(a == c);
}
执行结果: false, true
例2
public static void main(String[] args) {
Integer f1 = 100, f2 = 100, f3 = 250, f4 = 250;
System.out.println(f1 == f2);
System.out.println(f3 == f4);
}
执行结果: true, false
知识点一:自动拆箱与自动包装
概念
1.自动拆箱: 自动将包装器类型转换为基本数据类型;
2.自动包装: 自动将基本数据类型转换为包装器类型。
具体分析
例1中
Integer b = 8;
//自动装箱
//Integer a = new Integer(8);
//int c = 8;
System.out.println(a == c) // 自动拆箱
注意:
Integer与int比较时,会把Integer类型变量拆箱成int类型,然后比较。拆箱调用的是intValue()
方法。
对例1反编译看看(这里用jad
来反编译), Test
是例子中的类名。
下面命令将输出带字节码注释和源码
-a
表示用JVM字节格式来注解输出
;-o
表示无需确认直接覆盖输出
;-s
表示定义输出文件的扩展名
,默认的扩展名是jad
;java
表示我们想要的反编译后输出java
格式文件
jad
详细命令参见反编译小工具:jad常用命令介绍
jad -a -o -s java Test.class
反编译结果:
package test;
import java.io.PrintStream;
public class Test {
public Test() {
//
0
0:aload_0
//
1
1:invokespecial
#8
<Method void Object()>
//
2
4:return
}
public static void main(String args[]) {
Integer a = new Integer(8);
//
0
0:new
#16
<Class Integer>
//
1
3:dup
//
2
4:bipush
8
//
3
6:invokespecial
#18
<Method void Integer(int)>
//
4
9:astore_1
Integer b = Integer.valueOf(8);
//
5
10:bipush
8
//
6
12:invokestatic
#21
<Method Integer Integer.valueOf(int)>
//
7
15:astore_2
int c = 8;
//
8
16:bipush
8
//
9
18:istore_3
System.out.println(a == b);
//
10
19:getstatic
#25
<Field PrintStream System.out>
//
11
22:aload_1
//
12
23:aload_2
//
13
24:if_acmpne
31
//
14
27:iconst_1
//
15
28:goto
32
//
16
31:iconst_0
//
17
32:invokevirtual
#31
<Method void PrintStream.println(boolean)>
System.out.println(a.intValue() == c);
//
18
35:getstatic
#25
<Field PrintStream System.out>
//
19
38:aload_1
//
20
39:invokevirtual
#37
<Method int Integer.intValue()>
//
21
42:iload_3
//
22
43:icmpne
50
//
23
46:iconst_1
//
24
47:goto
51
//
25
50:iconst_0
//
26
51:invokevirtual
#31
<Method void PrintStream.println(boolean)>
//
27
54:return
}
}
可以看到第20
, 22
行,调用了Integer方法.valueOf(int)
自动装箱:
Integer b = 8;
Integer b = Integer.valueOf(8);
第36
行,调用了Integer方法.intValue()
自动拆箱:
System.out.println(a == c);
System.out.println(a.intValue() == c);
所以:a == c
的结果为true
例1中
Integer a = new Integer(8);
Integer b = 8;
System.out.println(a == b);
结果为何为false
?
刚讲到了
Integer b = 8;
调用了Integer方法.valueOf(int)
自动装箱,我们来看下.valueOf(int)
源码实现:
public static Integer valueOf(int i) {
assert IntegerCache.high >= 127;
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
也就是说最后会new
出来一个Integer对象或者返回缓存
中的数据。
注意:
+ ==
符号在比较对象
时,比较的是内存地址
;
+ 对于原始数据类型
(如上面a == c
)直接比对的是数据值
。
这里又涉及到了堆栈内存
了,需要清楚2点:
1. new
出来的对象或创建的数组
会在堆
中开辟内存空间;
2. 对象的引用
(即对象在堆内存
中的地址,如a
)和基本数据类型
存储在栈
中;
由此可知a
,b
引用指向的对象不是同一个,所以结果是false
知识点二:Integer缓存
在上面的.valueOf(int)
源码中我们能看到IntegerCache
类,看名称就知道是和缓存
有关。我们来看下Integer
类的静态内部类IntegerCache
源码实现:
private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer cache[];
static {
// high value may be configured by property
int h = 127;
String integerCacheHighPropValue =
sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
int i = parseInt(integerCacheHighPropValue);
i = Math.max(i, 127);
// Maximum array size is Integer.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
}
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() {}
}
该类中有一个静态数组
:
static final Integer cache[];
还有一个静态代码块
:
static {...}
既然是在static
静态类的静态代码快
中,也就是说在类加载的时候就会执行这部分代码逻辑。我们可以看到静态代码快
主要是向静态数组
中添加了[-128,127]
,也就要是说,调用方法.valueOf(int)
传入的int
值在[-128,127]
这个范围内时,直接从IntegerCache
的缓存数组中获取, 不会去在堆内存中new
。
[-128,127]
期间的数字比较常用,这一行为有助于节省内存、提高性能。
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
所以在例2中:
1.自动装箱
调用方法Integer.valueOf(int)
public static void main(String args[])
{
Integer f1 = Integer.valueOf(100);
//
0
0:bipush
100
//
1
2:invokestatic
#16
<Method Integer Integer.valueOf(int)>
//
2
5:astore_1
Integer f2 = Integer.valueOf(100);
//
3
6:bipush
100
//
4
8:invokestatic
#16
<Method Integer Integer.valueOf(int)>
//
5
11:astore_2
Integer f3 = Integer.valueOf(250);
//
6
12:sipush
250
//
7
15:invokestatic
#16
<Method Integer Integer.valueOf(int)>
//
8
18:astore_3
Integer f4 = Integer.valueOf(250);
//
9
19:sipush
250
//
10
22:invokestatic
#16
<Method Integer Integer.valueOf(int)>
//
11
25:astore
4
}
2.通过Integer.valueOf(int)
内部调用IntegerCache
类实现。
由于f1
,f2
对应的基本值在[-128,127]
之间,结果返回true
;
而f3
,f4
对应的基本值不在范围内,结果返回false
其他的包装类型也可以类似分析。
最后
以上就是无辜胡萝卜为你收集整理的int和Integer解析的全部内容,希望文章能够帮你解决int和Integer解析所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复