Integer缓存机制、装箱拆箱实现原理

概述

了解Java语言的应该都知道Integer这个类,知道它是基本数据类型int的包装器类,也知道它的用法等,但仅仅停留在[会用]这个层面上的程序员不是好司机。通过本文,我们将知道:

  • Integer核心源码
  • 自动装箱和自动拆箱实现原理
  • Integer缓存机制

自动装箱


请看下面代码:

public class IntegerTest {
    public static void main(String[] args) {
        Integer i1 = 1; //why
        System.out.println(i1);
    }
}

我们对上面的代码再熟悉不过,熟悉到我们可以不假思索地说出输出结果是1,熟悉到我们忘了问自己:
为什么可以把一个int类型的数赋值给Integer类型? 下面我们就一步步揭开这条语句的神秘面纱。<br />
通过工具javap来反编译IntegerTest.class(javap -c IntegerTest.class),部分结果截图如下:

image

从以上截图可以看到,编译器在编译Integer i1 = 1时调用了Integer.valueOf(int i)方法,我们来看看valueOf方法源码:

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

这是一个if-else结构语句,else语句体很好理解,通过调用Integer构造器创建一个新对象。但if语句体里面是什么鬼东西呢?其实是这样的,在Java中new对象会调用构造器创建一个新的对象,给它分配内存、管理它的生命周期等等等。为了解决每次new对象带来的存储分配、生命周期管理等问题,Java引入了 [对象缓存] ,通过将那些比较常用的对象缓存起来,这样就不必每次都重新创建一个新的对象,而只需将已缓存对象返回即可。这种缓存策略在Boolean、Byte、Char、Integer、Long中都有体现,今天我们看看缓存在Integer中是如何实现的:

#Integer.java
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) {
                try {
                    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);
                } catch( NumberFormatException nfe) {
                    // If the property cannot be parsed into an int, ignore it.
                }
            }
            high = h;

            cache = new Integer[(high - low) + 1];
            int j = low;
            for(int k = 0; k < cache.length; k++)
                cache[k] = new Integer(j++);

            // range [-128, 127] must be interned (JLS7 5.1.7)
            assert IntegerCache.high >= 127;
        }

        private IntegerCache() {}
    }

从以上源码中可以看出,Integer静态内部类 [IntegerCache] 默认将-128~127之间的整数对应的对象缓存在cache数组中,其中最大整数high可以通过JVM启动参数+XX:AutoBoxCacheMax=size修改,这样我们就可以根据应用实际情况灵活地调整来提高性能。
再回到valueOf(int i)方法,如果参数i的值在[IntegerCache.low, IntegerCache.high]之间,则返回IntegerCache.cache数组中对应的对象,否则,通过Integer构造器创建新的对象后返回。<br />以上就是Integer自动装箱的实现原理:编译器编译Integer i1 = 1语句时,通过调用Integer.valueOf(int i)方法实现自动装箱。

自动拆箱


再看以下代码:

public class IntegerTest {
    public static void main(String[] args) {
        Integer i1 = 1;
        int i2 = i1;  //why
        System.out.println(i2);
    }
}

这又是什么鬼?为什么Integer对象可以赋值给基本数据类型int? 同样,我们通过javap工具反编译IntegerTest.class,截图如下:

image

从以上反编译结果可以看到,编译器在编译int i2 = i1语句时,调用了Integer.intValue()方法

#Integer.java
public int intValue() {
        return value;
}

intValue()方法返回了对象的value值。

#Integer.java
private final int value;

public Integer(int value) {
        this.value = value;
}

以上就是Integer自动拆箱的实现原理:编译器编译int i2 = i1时,通过调用Integer.intValue()方法实现自动拆箱。

缓存机制


再看以下代码:

public class IntegerTest {
    public static void main(String[] args) {
        Integer i1 = 1;
        Integer i2 = 1;

        Integer i3 = 128;
        Integer i4 = 128;

        System.out.println(i1 == i2);  //true
        System.out.println(i3 == i4);  //false
    }
}

从自动装箱我们知道Integer将常用整数[-128~127]缓存在IntegerCache.cache对象数组中,所以引用i1和i2指向同一个对象,即i1 == i2;i3和i4的值128没有缓存在cache数组中,所以每次调用Integer.valueOf(int i)方法时,都会重新创建一个对象,因此引用i3和i4指向不同的对象,即i3 != i4。

欢迎留言交流

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,905评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,140评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,791评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,483评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,476评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,516评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,905评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,560评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,778评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,557评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,635评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,338评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,925评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,898评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,142评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,818评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,347评论 2 342

推荐阅读更多精彩内容

  • Java是一种可以撰写跨平台应用软件的面向对象的程序设计语言。Java 技术具有卓越的通用性、高效性、平台移植性和...
    Java小辰阅读 388评论 1 4
  • 1 方哲一直坚持,他和万柠第一次见面是在动车上。 万柠笑“你不会是在做梦吧,还是认错人了?我真的没有见过你。” 方...
    灰化肥会挥发发黑阅读 518评论 0 2
  • 当你的选择是为了向别人证明自己,你就被别人的看法绑架了。事实上,没有人真的有时间在意你怎样高尚、怎样正确,也真的没...
    知更鸟Robin阅读 108评论 0 0
  • 高二的时候和X住了两人寝室。 我本人比较半吊子,做事情没什么张罗。经常是进浴室洗完了一身水才发现没拿毛巾或者内...
    六代阅读 186评论 0 0
  • 初见—— 她手中漆黑的剑抵在他的咽喉处,剑柄包覆层层蛇皮,枯硬寒凉。 烛火昏黄,倒映在他眸中,却仿若坠了半片星空。...
    孟茶阅读 404评论 8 4