Java中自动装箱、拆箱引起耗时问题的示例分析

这篇文章主要介绍了Java中自动装箱、拆箱引起耗时问题的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。

创新互联公司专注于企业全网整合营销推广、网站重做改版、临沭网站定制设计、自适应品牌网站建设、HTML5商城网站建设、集团公司官网建设、成都外贸网站建设公司、高端网站制作、响应式网页设计等建站业务,价格优惠性价比高,为临沭等各大城市提供网站开发制作服务。

什么是自动装箱,拆箱

先抛出定义,Java中基础数据类型与它们的包装类进行运算时,编译器会自动帮我们进行转换,转换过程对程序员是透明的,这就是装箱和拆箱,装箱和拆箱可以让我们的代码更简洁易懂

耗时问题

在说 Java 的自动装箱和自动拆箱之前,我们先看一个例子。

这个错误我在项目中犯过(尴尬),拿出来共勉!

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)。

我们不妨先阅读下面的内容,再来分析、解决上述耗时的问题。

基本概念

自从 jdk1.5 之后就有了自动装箱(Autoboxing)和自动拆箱(AutoUnboxing)。

自动装箱,就是 Java 自动将原始(基本)类型转换成对应的封装器(对象)类型的过程,比如将 int 的变量转换成 Integer 对象,这个过程叫做装箱。

自动拆箱,就是 Java 自动将封装器(对象)类型转换成基本类型的过程,如将 Integer 对象转换成 int 类型值,这个过程叫做拆箱。

之所以称之为自动装箱和拆箱,是因为这些操作并非人工(程序猿)操作的,而是 Java 自带的一个特性。

下表是 Java 中的基本类型和对应的封装类型的对应表:

基本类型封装器类
intInteger
byteByte
longLong
floatfloat
doubleDouble
charCharacter
booleanBoolean

自动装箱示例:

int a = 3;
Integer b = a;

自动拆箱示例:

Integer b = new Integer(7);
int a = b;

Integer/int 自动拆箱和装箱

下面这段代码是 Integer 的源码中 valueOf 方法。

/**
 * 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);
}

我们在执行下面的这句代码,如下:

Integer i = 100;

上面的代码等同于下面的代码:

Integer i = Integer.valueOf(100);

结合上面的源码可以看出来,如果数值在 [-128,127] 之间(双闭区间),不会重新创建 Integer 对象,而是从缓存中(常量池)直接获取,从常量池中获取而不是堆栈操作,读取数据要快很多。

我们再来看一下常见的基础面试题(请给出打印结果),如下:

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 方法,源码如下:

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 方法有下面这句代码,如下:

Long sum = 0L;

很明显我们声明了一个 Long 的对象 sum,由于自动装箱,这句代码并没有语法上面的错误,编译器当然也不会报错。上面代码等同于如下代码:

Long sum = Long.valueof(0);

在 for 循环中,超过 [-128,127] 就会创建新的对象,这样不断的创建对象,不停的申请堆内存,程序执行自然也就比较耗时了。

修改一下代码,如下:

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");
}

执行时间大大缩短。

感谢你能够认真阅读完这篇文章,希望小编分享的“Java中自动装箱、拆箱引起耗时问题的示例分析”这篇文章对大家有帮助,同时也希望大家多多支持创新互联,关注创新互联行业资讯频道,更多相关知识等着你来学习!

网站栏目:Java中自动装箱、拆箱引起耗时问题的示例分析
URL链接:https://www.cdcxhl.com/article4/jeohoe.html

成都网站建设公司_创新互联,为您提供定制网站网站排名建站公司外贸网站建设网站收录关键词优化

广告

声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联

微信小程序开发