Java包装类性能优化:深入解析Integer享元模式的源码实现

news/2025/2/26 6:15:28

前言

Java中,每一个基本类型都有对应的包装类。其中,Integer作为最常用的包装类之一,其内部实现巧妙地运用了享元模式(Flyweight Pattern),通过对象缓存机制显著提升了性能。本文将深入剖析Integer类的享元模式实现,重点解析valueOf()方法的底层源码。

一、享元模式是什么?

享元模式是一种结构型设计模式,旨在通过共享技术有效地支持大量细粒度对象的复用。在Java包装类中,享元模式的核心思想是:

  • 缓存常用对象:对一定范围内的值进行预缓存
  • 减少对象创建:通过复用缓存对象降低内存开销
  • 提升性能:避免频繁的对象创建与垃圾回收

Java中,包装类如Integer便采用了享元模式以缓存常用的整数值,提升性能

Integer_11">二、Integer源码解析

valueOf()方法

Integer类的valueOf()方法是享元模式的核心,它通过缓存机制避免了频繁的对象创建。具体实现如下:

valueOf()方法源码:

java"> @IntrinsicCandidate
 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对象。

IntegerCache_27">IntegerCache类

IntegerCache类实现了缓存机制,缓存了从 -128 到 127 的所有Integer对象。其源码如下:

java">/**
 * Integer 缓存类(享元模式实现)
 * 用于缓存常用 Integer 对象,优化内存和性能
 */

 private static class IntegerCache {
    static final int low = -128;  // 缓存下限
    static final int high; // 缓存上限(可配置)
    static final Integer[] cache; // 缓存数组
    static Integer[] archivedCache; // 从 CDS 归档文件加载的缓存数组(JDK 17 新增)

    static {
        int h = 127;  // 默认缓存上限为 127
        
        // 尝试读取 JVM 参数配置的缓存上限
        String integerCacheHighPropValue =
            VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
        if (integerCacheHighPropValue != null) {
            try {
	            // 确保配置值不低于 127
                h = Math.max(parseInt(integerCacheHighPropValue), 127);
                
                // 防止缓存数组大小超过 Integer.MAX_VALUE
                // 计算逻辑:数组最大长度 = Integer.MAX_VALUE - (-low) -1
                h = Math.min(h, Integer.MAX_VALUE - (-low) -1);
            } catch( NumberFormatException nfe) {
                // 忽略格式错误(保持默认值 127)
            }
        }
        high = h; // 确定最终缓存上限

        // 尝试从 CDS 归档文件加载缓存(JDK 17 优化点)
        CDS.initializeFromArchive(IntegerCache.class);
        int size = (high - low) + 1;

        // 动态生成缓存数组的条件:
        // 1. 归档缓存不存在 或 2. 当前需要的缓存大小 > 归档缓存长度
        if (archivedCache == null || size > archivedCache.length) {
        	// 创建新缓存数组
            Integer[] c = new Integer[size];
            int j = low; // 起始值
            for(int i = 0; i < c.length; i++) {
                c[i] = new Integer(j++); // 预生成所有缓存对象
            }
            archivedCache = c; // 更新归档缓存
        }
        cache = archivedCache; // 指向最终缓存数组
        
        // 断言确保缓存上限至少为 127(符合 JLS 规范)
        assert IntegerCache.high >= 127;
    }

	// 私有构造方法(防止外部实例化)
    private IntegerCache() {}
}

如何提高性能?

通过享元模式Integer.valueOf()方法只会创建缓存范围内的对象,而不需要每次都new一个新的Integer对象。这一机制显著降低了内存开销,避免了不必要的垃圾回收。

三、面试题

以下代码会输出什么?

java">public class Main {
    public static void main(String[] args) {

        Integer i1 = new Integer(100);
        Integer i2 = new Integer(100);

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

注意:这里Integer是对象,==比较的是对象的引用,而不是对象的内容。

java">public class Main {
 public static void main(String[] args) {
 
 Integer i1 = 100;  // 自动装箱机制,在底层会自动调用静态方法valueOf的得到一个Integer对象
 Integer i2 = 100;
 Integer i3 = 200;
 Integer i4 = 200;
 
 System.out.println(i1==i2); // true
 System.out.println(i3==i4); // false
 }
}

补充Integer的常用成员方法
在这里插入图片描述
注意:8中包装类中,除了Character都有对应的parseXxx的方法,进行类型转换


http://www.niftyadmin.cn/n/5868167.html

相关文章

Java进阶学习笔记64——IO流

IO流&#xff1a; 输入输出流&#xff0c;就是读写数据的。 IO流的应用场景&#xff1a; 怎么去学习IO流&#xff1f; 1、先搞清楚IO流的分类、体系&#xff1f; 2、再挨个学习每个IO流的作用、用法。 IO流的分类&#xff1a; 按流的方向分为&#xff1a; 按流中数据的最小…

一文掌握python中正则表达式的各种使用

文章目录 1. 正则表达式基础1.1 常用元字符1.2 基本用法 2. 正则表达式高级功能2.1 分组捕获2.2 命名分组2.3 非贪婪匹配2.4 零宽断言2.5 编译正则表达式2.6 转义字符 3. 常见应用场景3.1 验证邮箱格式3.2 提取 URL3.3 提取日期3.4 提取HTML中的链接3.5 提取HTML中的图片链接3.…

排序趟数问题

1. 冒泡排序 趟数&#xff1a;最多 n-1 趟&#xff08;n为元素个数&#xff09;每趟操作&#xff1a;比较相邻元素&#xff0c;将最大元素“冒泡”到末尾。优化&#xff1a;若某趟无交换&#xff0c;可提前终止&#xff08;如数组已有序时仅需1趟&#xff09;。示例&#xff1…

如何获取zookeeper中的注册内容,在Java项目中演示

我来为你展示如何在Java项目中通过ZooKeeper获取已注册的内容。下面提供一个完整的示例&#xff0c;包括连接ZooKeeper、获取节点数据以及处理常见情况的代码。 示例代码 以下代码演示了如何从ZooKeeper中获取注册内容&#xff1a; import org.apache.zookeeper.*; import ja…

smolagents学习笔记系列(六)Secure code execution

这篇文章锁定官网教程 Secure code execution 章节的内容&#xff0c;主要介绍了smolagents是如何安全地执行LLM的输出结果。 官网链接&#xff1a;https://huggingface.co/docs/smolagents/v1.9.2/en/tutorials/secure_code_execution 为了不浪费你的时间&#xff0c;下面这…

JAVAweb之过滤器,监听器

文章目录 过滤器认识生命周期FilterConfigFilterChain过滤器执行顺序应用场景代码 监听器认识ServletContextListenerHttpSessionListenerServletRequestListener代码 过滤器 认识 Java web三大组件之一&#xff0c;与Servlet相似。过滤器是用来拦截请求的&#xff0c;而非处…

python绑定udp时使用127.0.0.1作为ip,无法sendto,报错Invalid argument

在 Python 中使用 UDP 套接字进行通信时&#xff0c;绑定127.0.0.1作为 IP 地址后无法使用sendto方法发送数据&#xff0c;可能由多种原因导致 这里是其中一个原因&#xff1a; 127.0.0.1 是本地回环地址&#xff0c;只能用于本机内部的进程间通信&#xff0c; 如果你绑定到 …

《OpenCV》—— 背景建模

背景建模是什么&#xff1f; 背景建模的意义&#xff1f; 通过背景建模&#xff0c;我们可以实现很多应用&#xff0c;例如运动检测、目标跟踪 背景建模的方法 帧差法 帧差法的原理 基于 K 近邻的前景分割算法&#xff08;KNN&#xff09; 原理 基于 K 近邻的前景分割算法…