栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java中自动装箱、自动拆箱与Integer缓存(含源码)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java中自动装箱、自动拆箱与Integer缓存(含源码)

1. 前言

自动装箱和自动拆箱是什么?Integer缓存是什么?它们之间有什么关系?

先来看一道题目。

Integer a = new Integer(1);
Integer b = new Integer(1);
System.out.println(a==b);

Integer c = 1;
Integer d = 1;
System.out.println(c==d);

Integer e = 128;
Integer f = 128;
System.out.println(e==f);

先答,后看答案。

答案是false true false,你答对了吗?

既然一块出现了,就一起串一下知识点

2. 包装类

Java中基本数据类型有八种,可以分为三类:

  • 字符型:char
  • 布尔型:boolean
  • 数值型:byte short int long float double

包装类是将八种基本数据类型包装为了类,使它们可以使用Java的三大特性:封装、继承、多态。对应关系如下:

基本数据类型对应的包装类
byteByte
shortShort
intInteger
longLong
floatFloat
doubleDouble
booleanBoolean
charCharacter

数值型对应的六个包装类都继承于Number类。

3. 自动装箱与自动拆箱

八种基本数据类型对应八种包装类,那么它们是怎么进行数据转换的?

//基本数据类型转包装类

//1.有参构造
Integer a = new Integer(1);
//2.实际上,有参构造的参数也可以是字符串,不过要使用正确的数据,“123abc”不可能会转换为Integer类型
Integer b = new Integer("123");
//3.valueOf()
Integer c = Integer.valueOf(123);

//包装类转基本数据类型(xxxValue()  float是floatValue() double是doublevalue())
int d = a.intValue();

以上的形式都是比较符合认知的,获取一个对象可以通过new或者调用某个方法,获取一个值就调用对象的某个属性。

Java 5.0之后可以不用这么麻烦了,增加了自动装箱和自动拆箱的新特性,实际上两个概念非常好理解。

int a = 10;
Integer b = a;  //自动装箱

int c = b;  //自动拆箱

乍一看,对象=数值的这种形式并不符合认知,但是借助于自动装箱和自动拆箱就可以实现。实际上,编译器还是借助于valueOf()和xxxValue()实现的。

我们来看一下valueOf()源码。

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

valueOf()并不是简单地返回Integer对象,而是先进行了一次判断,输入的数据符合某个范围的话,将会返回一个特定的对象,从注释上来看,这个范围默认是[-128,127],并且可能是更大的范围;而超过这个范围就会返回new的对象。而使用到的IntegerCache数据就是Integer的缓存了。

4. Interger缓存

数值计算日常使用比较频繁,那如果不停的去new Integer对象的话,开销会非常大,所以,Java在执行程序时会自动生成一个静态数组作为缓存,Integer默认对应的缓存数组范围在[-128,127],只要数据在这个范围内,就可以从缓存中拿到相应的对象。

看一下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) {
            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() {}
}

可以看到,IntegerCache是Integer的静态内部类,valueOf()调用的IntegerCache.cache就是一个数组对象,数组的大小取决于范围内的最大值和最小值,默认是[-128,127],当然,(注释上说)也可以通过JVM修改这个范围(这我不了解)。然后数组内的元素都会被赋一个Integer对象,缓存也就形成了。

存在数组缓存,也就意味着,如果取值在[-128,127],使用valueOf()或者自动装箱创建的Integer对象都是在数组中取出,因此对象指向的内存地址是完全一样的。而如果用new或者是超出这个范围都要重新创建对象。

当然,不止Integer有缓存机制,Byte、Short、Long、Character都具有缓存机制。其中Byte,Short,Integer,Long的范围为 -128 到 127,Character的范围为 0 到 127。

5. 回答题目
Integer a = new Integer(1);
Integer b = new Integer(1);
System.out.println(a==b);

Integer c = 1;
Integer d = 1;
System.out.println(c==d);

Integer e = 128;
Integer f = 128;
System.out.println(e==f);

1.new创建的两个对象,即使值相同,指向的内存地址也是不同的,使用==进行比较返回结果为false

2.自动装箱和缓存机制,两个对象实际上是相同的,返回结果为true

3.超出缓存范围,执行时会new新对象,两个对象不同,返回结果为false

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/445846.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号