6

通过源码了解Java的自动装箱拆箱 - 一个程序员的成长

 2 years ago
source link: https://www.cnblogs.com/bingfengdada/p/16169715.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

什么叫装箱 & 拆箱?

将int基本类型转换为Integer包装类型的过程叫做装箱,反之叫拆箱。

首先看一段代码

public static void main(String[] args) {
    Integer a = 127, b = 127;
    Integer c = 128, d= 128;
    System.out.println(a == b); // true
    System.out.println(c == d); // false
}

不知道还有没有人不知道这段代码出现true和false的原因。由此我们引出了Java装箱的这个操作。我们带着疑问去进行分析。

装箱(valueOf())

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

我们可以发现,在最开始有一个判断,如果这个值的范围在[-128,127]之间,那么就从这个缓存(Integer数组)中取,如果不在这个范围那么直接new一个。

为什么要有[-128,127]的缓存?

我说说的理解,因为在我们的业务中,可能存在各种状态和标识等Integer类型的字段,这些值一般都是0,1,2,3之类的,而且出现的比较频繁,如果没有缓存,那么就需要频繁的new对象,然后再释放,就非常消耗内存空间,所以对于这个缓存就出现了,可以极大的帮助我们优化一些空间上的浪费。

为什么是[-128,127]?

这个我看了一下,具体为什么这里就不详说了,主要还是依赖计算机基础知识,在你了解了什么是原码、反码、补码。就很容易知道为什么是这个范围区间了。

这个值也是可以通过启动参数进行更改的。

-XX:AutoBoxCacheMax=(size)

自动装箱带来的性能问题

那么看到现在你应该明白上面代码出现不同结果的原因了,那么你有没有想过,比如我们业务中一个for循环中,出现了统计数据类似这样的操作,如果存在自动装箱,那么会出现什么问题?我们看下面一段代码。

public static void main(String[] args) {
    long startTime = System.currentTimeMillis();
    Integer count = 0;
    // int count = 0;
    for (int i = 0; i < 5000000; i++) {
        count += i;
    }
    System.out.println("计算时长:" + (System.currentTimeMillis() - startTime) + " ms");
}

// 执行结果:
// Integer 计算时长:51 ms
// int 计算时长:6 ms

那么通过执行结果可以明显的发现自动装箱频繁的new对象、分配内存,造成时间和空间上的性能损耗。

通过上面的源码阅读和测试分析,我们可以得出结论,我们平时在进行计算统计,或者方法入参的时候,应该尽量的避免这种类型转换的问题。来提升我们整个代码的执行效率。

拆箱(intValue)

拆箱总体没有什么复杂的逻辑,直接返回这个数值的基本类型。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK