Java包装类中的缓存机制

本文将介绍Java中Integer的缓存相关知识。这是在Java 5中引入的一个有助于节省内存,提高性能的功能。首先看一个使用Integer的示例代码,从中学习其缓存行为。接着我们将为为什么这么实现以及他到底是如何实现的。你能猜出下面的的Java程序的输出结果吗。如果你的结果和真正结果不一样,那么你就要好好看看本文了。

package com.javapapers.java;

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

        Integer integer1 = 3;
        Integer integer2 = 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");

    }
}

我们普遍认为上面的两个判断的结果都是假的。虽然比较的值是相等的,但是由于比较的是对象,而对象的引用不一样,所以会认为两个如果判断都是错误的。在Java的中,==比较的是对象应用,而equals比较的的英文值。所以,在这个例子中,不同的对象有不同的引用,所以在进行比较的时候都将返回错误。奇怪的是,这里两个类似的,如果条件判断返回不同的布尔值。

上面这段代码真正的输出结果:

integer1 == integer2
integer3 != integer4

Java的中整数的缓存实现

在Java 5中,在Integer的操作上引入了一个新功能来节省内存和提高性能。整型对象通过使用相同的对象引用实现了缓存和重用。

适用于整数值区间-128至+127。

只适用于自动装箱。使用构造函数创建对象不适用。

的Java的编译器把基本数据类型自动转换成封装类对象的过程叫做自动装箱,使用相当于valueOf方法:

Integer a = 10; //this is autoboxing
Integer b = Integer.valueOf(10); //under the hood

现在我们知道了这种机制在源码中哪里使用了,那么接下来我们就看看JDK中的valueOf。下面方法的英文JDK 1.8.0 build 25的实现:

/**
     * Returns an {@code Integer} instance representing the specified
     * {@code int} value.  If a new {@code Integer} instance is not
     * required, this method should generally be used in preference to
     * the constructor {@link #Integer(int)}, as this method is likely
     * to yield significantly better space and time performance by
     * caching frequently requested values.
     *
     * This method will always cache values in the range -128 to 127,
     * inclusive, and may cache other values outside of this range.
     *
     * @param  i an {@code int} value.
     * @return an {@code Integer} instance representing {@code i}.
     * @since  1.5
     */
    public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }

在创建对象之前先从IntegerCache.cache中寻找。如果没找到才使用新新建对象。

IntegerCache类

IntegerCache是整数中类定义的一个private static的内部类。接下来看看他的定义。

  /**
     * Cache to support the object identity semantics of autoboxing for values between
     * -128 and 127 (inclusive) as required by JLS.
     *
     * The cache is initialized on first usage.  The size of the cache
     * may be controlled by the {@code -XX:AutoBoxCacheMax=} option.
     * During VM initialization, java.lang.Integer.IntegerCache.high property
     * may be set and saved in the private system properties in the
     * sun.misc.VM class.
     */

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

其中的javadoc详细的说明了缓存支持-128到127之间的自动装箱过程。最大值127可以通过-XX:AutoBoxCacheMax=size修改。缓存通过一个用于循环实现。从低到高并创建尽可能多的整数并存储在一个整数数组中。这个缓存会在整数类第一次被使用的时候被初始化出来。以后,就可以使用缓存中包含的实例对象,而不是创建一个新的实例(在自动装箱的情况下)。

实际上这个功能在Java 5中引入的时候,范围是固定的-128至+127.后来在Java 6中,可以通过java.lang.Integer.IntegerCache.high设置最大值。这使我们可以根据应用程序的实际情况灵活地调整来提高性能。到底是什么原因选择这个-128到127范围呢?因为这个范围的数字是最被广泛使用的。在程序中,第一次使用Integer的时候也需要一定的额外时间来初始化这个缓存。

的Java语言规范中的缓存行为

Boxing Conversion部分的Java语言规范(JLS)规定如下:

如果一个变量p的值是:

-128至127之间的整数(§3.10.1)

true和false的布尔值(§3.10.3)

‘\ u0000‘至‘\ u007f‘之间的字符(§3.10.4)

中时,将p包装成一个和b两个对象时,可以直接使用一个== b判断一个和b的值是否相等。

其他缓存的对象

这种缓存行为不仅适用于整数对象。我们针对所有的整数类型的类都有类似的缓存机制。

有ByteCache用于缓存字节对象

有ShortCache用于缓存短对象

有LongCache用于缓存长对象

有CharacterCache用于缓存字对象

ByteShortLong有固定范围:-128到127对于Character,范围是0到127。除了Integer以外,这个范围都不能改变。

原文地址:https://www.cnblogs.com/lujiahua/p/11408598.html

时间: 2024-07-29 13:30:33

Java包装类中的缓存机制的相关文章

linux套接字通信之recv中的缓存机制的研究

以前一直有这么一个小小的疑惑,当一个进程注册一个套接字后,如果这个套接字没有被调用recv函数接受数据包,那么这个套接字能接受到数据包吗? 或者这样说,如果我的程序注册了一个套接字去接受数据包,但是每收到一个数据包都需要很长一段时间处理,并且在处理数据包的途中recv函数使没有被调用的,那么如果程序再处理数据包的途中有数据包到来,那我的程序会不会漏过这些数据包(那个包到达的时候程序在处理别的包,而没有调用recv函数)? 答案是不会的.事实上linux中会为每个套接字建立缓存,当属于套接字的包到

Java交换值及中间缓存机制

 实现交换int a,b的值的函数,C++可以采用引用或指针传递的方法,当Java不行: 因为Java的参数传递机制与C++不同(http://blog.csdn.net/woliuyunyicai/article/details/44096043), 如下方法均不能够实现: public void swap(int x, int y) { int temp = x; x = y; y = x; } public void swap(Integer x, Integer y) { Integ

解析Java分布式系统中的缓存架构(上)

作者 陈彩华 文章转载交流请联系 [email protected] 本文主要介绍大型分布式系统中缓存的相关理论,常见的缓存组件以及应用场景. 1 缓存概述 2 缓存的分类 缓存主要分为以下四类 2.1 CDN缓存 基本介绍 CDN(Content Delivery Network 内容分发网络)的基本原理是广泛采用各种缓存服务器,将这些缓存服务器分布到用户访问相对集中的地区或网络中,在用户访问网站时,利用全局负载技术将用户的访问指向距离最近的工作正常的缓存服务器上,由缓存服务器直接响应用户请求

hibernate中的缓存机制

一.为什么要用Hibernate缓存? Hibernate是一个持久层框架,经常访问物理数据库. 为了降低应用程序对物理数据源访问的频次,从而提高应用程序的运行性能. 缓存内的数据是对物理数据源中的数据的复制,应用程序在运行时从缓存读写数据,在特定的时刻或事件会同步缓存和物理数据源的数据. 二.Hibernate缓存原理是怎样的?Hibernate缓存包括两大类:Hibernate一级缓存和Hibernate二级缓存. 1.Hibernate一级缓存又称为“Session的缓存”. Sessio

JAVA基础篇三(Java,C++中的异常机制)

由于C++和JAVA有很多相似之处,又有很多细微的差别,所以在学习JAVA的过程中对两种语言进行对比学习. 1.C++的异常机制 C++中处理异常的过程是这样的:在执行程序发生异常,可以不在本函数中处理,而是抛出一个错误信息,把它传递给上一级的函数来解决,上一级解决不了,再传给其上一级,由其上一级处理.如此逐级上传,直到最高一级还无法处理的话,运行系统会自动调用系统函数terminate,由它调用abort终止程序.这样的异常处理方法使得异常引发和处理机制分离,而不在同一个函数中处理.这使得底层

029.ASP.Net中的缓存机制

ASP.Net中的缓存 输出缓存1. 整页缓存 缓存整个页面的输出结果 Duration 缓存时间:绝对过期 VaryByParam:依据参数值缓存,没有为None,多个用;分割 Location:缓存的位置 代码在 ftp 的 Cache目录内 2. 片段缓存 使用用户控件,将需要缓存的内容放入用户控件 指定shared=true,可以多个页面共享缓存结果 3.Substitution控件 在整页都缓存的情况下,可以部分更新内容 配置MethodName属性,对应的.cs中的方法原型是 str

分享知识-快乐自己:论Hibernate中的缓存机制

Hibernate缓存 缓存: 是计算机领域的概念,它介于应用程序和永久性数据存储源之间. 缓存: 一般人的理解是在内存中的一块空间,可以将二级缓存配置到硬盘.用白话来说,就是一个存储数据的容器.我们关注的是,哪些数据需要被放入二级缓存. 缓存作用: 降低应用程序直接读写数据库的频率,从而提高程序的运行性能.缓存中的数据是数据存储源中数据的拷贝.缓存的物理介质通常是[内存]. Hibernate缓存分类: 1):Session缓存(又称作事务缓存):Hibernate内置的,不能卸除. 缓存范围

一次读懂mybatis中的缓存机制

缓存功能针对于查询(没听说果UPDATE,INSERT语句要缓存什么,都是直接执行的) 默认情况下,mybatis会启用一级缓存. 如果使用同一个session对象调用了相同的SELECT语句,则直接会从缓存中返回结果,而不是再查询一次数据库. 注意:session调用commit或close方法后,这个session中的一级缓存就会被清空 例如: 根据日志输出可以看出,下面代码只会发出一条sql查询语句 SqlSession sqlSession = MyBatisSqlSessionFact

Android中的缓存机制与实现

分步阅读 Android开发本质上就是手机和互联网中的web服务器之间进行通信,就必然需要从服务端获取数据,而反复通过网络获取数据是比较耗时的,特别是访问比较多的时候,会极大影响了性能,Android中可通过二级缓存来减少频繁的网络操作,减少流量.提升性能. 方法/步骤 二级缓存工作机制 所谓二级缓存实际上并不复杂,当Android端需要获得数据时比如获取网络中的图片,我们首先从内存中查找(按键查找),内存中没有的再从磁盘文件或sqlite中去查找,若磁盘中也没有才通过网络获取:当获得来自网络的