记住这道必考题:不是所有包装类型都有缓存的!

2023-11-10 18:45:23 浏览数 (3)

大家好,欢迎来到程序视点!我是小二哥。

上一篇文章中,我们分辨了基本类型和包装类型的区别。今天我们来聊聊包装类型的缓存机制。

笔试题

关于包装类型的缓存机制,几乎是一道必考题。题例大概如下:

代码语言:javascript复制
Integer a = 100;
Integer b = 100;
System.out.println(a == b);
代码语言:javascript复制
Integer a = 200;
Integer b = 200;
System.out.println(a == b);

请给出上面两处打印的结果。答案分别是:truefalse

ps:如果你能正确给出答案,且能明白其中缘由,请直接查看文末最后一题。如果文末的题目你也能做对,且明白其中原因,那以下内容就可以直接跳过了;反之,请详细阅读本文。

同样都是包装类型的赋值,比较结果却不一样,这是怎么回事呢?这和自动装箱有关。

把基本类型转换成包装类型的过程叫做装箱(boxing)。

自动装箱的发生,就涉及到包装类型的缓存机制。(我们会在下一篇文章中来说明这个知识点)

包装类型的缓存源码

Java 基本数据类型的包装类型的大部分都用到了缓存机制来提升性能。

先记住下面这四句话:

Byte,Short,Integer,Long 这 4 种包装类默认创建了数值 [-128,127] 的相应类型的缓存数据。 Character 创建了数值在 [0,127] 范围的缓存数据。 Boolean 直接返回 True or False。 两种浮点数类型的包装类 Float和Double 没有实现缓存机制。

自动装箱是通过包装类的 valueOf() 方法完成的。 因此,我们去看它们 valueOf() 方法的源码即可。

Integer 缓存源码:

代码语言:javascript复制
public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i   (-IntegerCache.low)];
    return new Integer(i);
}
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;
        ...
        high = h;

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

Integer 的缓存是由一个Integer数组来实现的(上面哪个 cache 数组)。

ps:我这里只摘取了核心的逻辑。详细源码,请自行查阅JDK源码!

同理,Character 缓存源码:

代码语言:javascript复制
public static Character valueOf(char c) {
    if (c <= 127) { // must cache
      return CharacterCache.cache[(int)c];
    }
    return new Character(c);
}

private static class CharacterCache {
    private CharacterCache(){}
    static final Character cache[] = new Character[127   1];
    static {
        for (int i = 0; i < cache.length; i  )
            cache[i] = new Character((char)i);
    }

}

还有Boolean 缓存源码:

代码语言:javascript复制
public static Boolean valueOf(boolean b) {
    return (b ? TRUE : FALSE);
}

至于Byte,Short和Long的缓存,就请大家抽空自己翻翻了。这里就不粘贴了。

特别注意:Float和Double 没有实现缓存机制。 我们来瞧瞧Double的valueOf()方法:

代码语言:javascript复制
public static Double valueOf(double d) {
    return new Double(d);
}

在double进行自动装箱时,返回的是new出来的一个对象,即每一个都是不同的。

最后一题

根据上面的知识,看看下面这道题的输出结果:

代码语言:javascript复制
Integer i1 = 33;
Integer i2 = 33;
System.out.println(i1 == i2);

Float i11 = 333f;
Float i22 = 333f;
System.out.println(i11 == i22);

Double i3 = 1.2;
Double i4 = 1.2;
System.out.println(i3 == i4);

答案分别是:truefalsefalse。你答对了吗?

1 人点赞