先抛出定义,java中基础数据类型与它们的包装类进行运算时,编译器会自动帮我们进行转换,转换过程对程序员是透明的,这就是装箱和拆箱,装箱和拆箱可以让我们的代码更简洁易懂
耗时问题
在说 java 的自动装箱和自动拆箱之前,我们先看一个例子。
这个错误我在项目中犯过(尴尬),拿出来共勉!
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
private static long getcounterresult() {
long sum = 0l;
final int length = integer.max_value;
for (int i = 0; i < length; i++) {
sum += i;
}
return sum;
}
public static void main(string[] args) {
long startcounttime = system.currenttimemillis();
long result = getcounterresult();
long endcounttime = system.currenttimemillis();
system.out.println("result = " + result + ", and take up time : " + (endcounttime - startcounttime) / 1000 + "s");
}
|
在我的电脑(macos 64位系统,配置较高),打印结果如下:
result = 2305843005992468481, and take up time : 12s
居然使用了 12s,是可忍叔不可忍,再正常不过的代码怎么会耗时这么久呢?如果在配置差一点的电脑上运行耗时会更久(惊呆了.jpg)。
我们不妨先阅读下面的内容,再来分析、解决上述耗时的问题。
基本概念
自动装箱,就是 java 自动将原始(基本)类型转换成对应的封装器(对象)类型的过程,比如将 int 的变量转换成 integer 对象,这个过程叫做装箱。
自动拆箱,就是 java 自动将封装器(对象)类型转换成基本类型的过程,如将 integer 对象转换成 int 类型值,这个过程叫做拆箱。
之所以称之为自动装箱和拆箱,是因为这些操作并非人工(程序猿)操作的,而是 java 自带的一个特性。
下表是 java 中的基本类型和对应的封装类型的对应表:
| 基本类型 | 封装器类 |
|---|---|
| int | integer |
| byte | byte |
| long | long |
| float | float |
| double | double |
| char | character |
| boolean | boolean |
自动装箱示例:
|
1
2
|
int a = 3;
integer b = a;
|
自动拆箱示例:
|
1
2
|
integer b = new integer(7);
int a = b;
|
integer/int 自动拆箱和装箱
下面这段代码是 integer 的源码中 valueof 方法。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
/**
* returns an {@code integer} instance representing the specified
* {@code int} value. if a new {@code integer} instance is not
* required, this method should generally be used in preference to
* the constructor {@link #integer(int)}, as this method is likely
* to yield significantly better space and time performance by
* caching frequently requested values.
*
* this method will always cache values in the range -128 to 127,
* inclusive, and may cache other values outside of this range.
*
* @param i an {@code int} value.
* @return an {@code integer} instance representing {@code i}.
* @since 1.5
*/
public static integer valueof(int i) {
// 如果i的值大于-128小于127则返回一个缓冲区中的一个integer对象
if (i >= integercache.low && i <= integercache.high)
return integercache.cache[i + (-integercache.low)];
// 否则返回 new 一个integer 对象
return new integer(i);
}
|
我们在执行下面的这句代码,如下:
|
1
|
integer i = 100;
|
上面的代码等同于下面的代码:
|
1
|
integer i = integer.valueof(100);
|
结合上面的源码可以看出来,如果数值在 [-128,127] 之间(双闭区间),不会重新创建 integer 对象,而是从缓存中(常量池)直接获取,从常量池中获取而不是堆栈操作,读取数据要快很多。
我们再来看一下常见的基础面试题(请给出打印结果),如下:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
public static void main(string[] args) {
// ⓵
integer a = new integer(121);
integer b = new integer(121);
system.out.println(a == b);
// ⓶
integer c = 121;
integer d = 121;
system.out.println(c == d);
// ⓷
integer e = 129;
integer f = 129;
system.out.println(e == f);
// ⓸
int g = 50;
integer h = new integer(50);
system.out.println(g == h);
}
|
分析结果:
⓵: false, 两个对象进行比较分别指向了不同堆内存
⓶: true, 自动装箱且数值在 [-128,127] 之间(双闭区间)
⓷: false, 自动装箱且数值不在 [-128,127] 之间(双闭区间)
⓸: true, 自动拆箱且数值在 [-128,127] 之间(双闭区间)
解析耗时问题
类 long 对应的也有一个 valueof 方法,源码如下:
|
1
2
3
4
5
6
7
|
public static long valueof(long l) {
final int offset = 128;
if (l >= -128 && l <= 127) { // will cache
return longcache.cache[(int)l + offset];
}
return new long(l);
}
|
这个和 integer 的很像,道理上面说过,这里不再赘述。
在开篇的例子中,getcounterresult 方法有下面这句代码,如下:
|
1
|
long sum = 0l;
|
很明显我们声明了一个 long 的对象 sum,由于自动装箱,这句代码并没有语法上面的错误,编译器当然也不会报错。上面代码等同于如下代码:
|
1
|
long sum = long.valueof(0);
|
在 for 循环中,超过 [-128,127] 就会创建新的对象,这样不断的创建对象,不停的申请堆内存,程序执行自然也就比较耗时了。
修改一下代码,如下:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
private static long getcounterresult() {
// 修改为普通的基本类型数据
long sum = 0l;
final int length = integer.max_value;
for (int i = 0; i < length; i++) {
sum += i;
}
return sum;
}
public static void main(string[] args) {
long startcounttime = system.currenttimemillis();
long result = getcounterresult();
long endcounttime = system.currenttimemillis();
system.out.println("result = " + result + ", and take up time : " + (endcounttime - startcounttime) / 1000 + "s");
}
|
执行时间大大缩短。
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对快网idc的支持。
原文链接:http://www.veryitman.com/2019/04/07/Java-自动装箱、拆箱引起的耗时/
相关文章
- 64M VPS建站:如何选择最适合的网站建设平台? 2025-06-10
- ASP.NET本地开发时常见的配置错误及解决方法? 2025-06-10
- ASP.NET自助建站系统的数据库备份与恢复操作指南 2025-06-10
- 个人网站服务器域名解析设置指南:从购买到绑定全流程 2025-06-10
- 个人网站搭建:如何挑选具有弹性扩展能力的服务器? 2025-06-10
- 2025-07-10 怎样使用阿里云的安全工具进行服务器漏洞扫描和修复?
- 2025-07-10 怎样使用命令行工具优化Linux云服务器的Ping性能?
- 2025-07-10 怎样使用Xshell连接华为云服务器,实现高效远程管理?
- 2025-07-10 怎样利用云服务器D盘搭建稳定、高效的网站托管环境?
- 2025-07-10 怎样使用阿里云的安全组功能来增强服务器防火墙的安全性?
快网idc优惠网
QQ交流群
-
2025-05-29 35
-
2025-05-25 77
-
2025-06-04 90
-
2025-05-27 78
-
2025-05-25 40

