聊聊 Java 中那些缓存机制

Posted by Deadline on March 25, 2016

0x00

前段时间校稿的时候看到一道有意思的题目

package com.javapapers.java;

public class JavaIntegerCache {
    public static void main(String... strings) {

        Integer integer1 = 3;
        Integer integer2 = 3;
        //Integer integer1 = new Integer(3);
        //Integer integer2 = new Integer(3);

        if (integer1 == integer2)
            System.out.println("integer1 == integer2");
        else
            System.out.println("integer1 != integer2");

        Integer integer3 = 300;
        Integer integer4 = 300;

        if (integer3 == integer4)
            System.out.println("integer3 == integer4");
        else
            System.out.println("integer3 != integer4");

    }
}

我知道它们会不相等,因为两个都是对象,对象用 == 比较的实际上是内存地址,那结果都一样的话写出来就没有意思了。肯定是有一个相等一个不相等。

来公布下结果:

integer1 == integer2
//integer1 != integer2
integer3 != integer4

为什么呢? 因为缓存!
在 Java 5 版本中为了提升性能引入了一个特性,就是会自动缓存 -128~127 的整数。就拿上面的示例代码来说,对象 integer1 和 integer2 实际上是同一个对象,在内存中的位置相同。

注意注意!!!
缓存 Integer 对象有个重要的前提条件就是:自动装箱的对象才会缓存!(原始类型和封装类型的自动装箱、拆箱就不再详细介绍了)

如果把上面的代码改改就是另外的结果了!

Integer integer1 = new Integer(3);
Integer integer2 = new Integer(3);

这种情况是不会缓存哒!记住咯!

为什么是这个范围的数呢?
因为这个范围的数使用的最多。

这个范围能改吗?
可以,VM arguments 设置参数 -XX:AutoBoxCacheMax=size 就能修改这个值的范围。-128~size

其他类型自动装箱的时候也会缓存么?
会的,Byte、Short、Long 有固定范围: -128 ~ 127。对于 Character: 范围是 0 到 127。(通过参数修改范围只对 Integer 有效)

0x01

到这里还没有完!因为我联想到了 String 的常量池。

面试的时候经常会碰到像下面这样的题目。

String a = new String("a");
String b = "a";
String c = "a";

//注意是 == ,不是比较对象的字面值哦
System.out.println(a == b);
System.out.println(b == c);

求输出结果。

false
true

如果按照上面缓存整数的方式思考的话,估计也能猜得到答案。
new 出来的对象 a 和直接赋值的对象 b 是不相等的,虽然值一样。
但是同样两个都是直接赋值创建的对象 b、c 会相等。

直接字面值创建的 String 对象会先在常量池中查找是否已经存在,如果存在则直接返回该引用,没有就加入到常量池中。
new 创建的对象和常量池无关。无论常量池中是否已经存在,都会创建新对象。

intern 方法会先去常量池查找,找到了就返回,找不到就加进常量池再返回。
a.intern() == b 为 true

不知道 Java 中还有哪些类似的缓存策略。


There are no comments on this post.