JDK源码细节——Long与Integer的缓存问题

本文探讨了JDK1.8中Long和Integer包装类的缓存特性。当创建Long对象时,对于-128到127之间的数值,会复用缓存中的实例,导致"=="比较返回true。而对于Integer,除了默认-128到127的缓存范围,还可以通过JVM参数调整上限。理解这些细节有助于避免潜在问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

也是在道友的面经中看到这个问题,然后去查了一下,也自己去看了源码核实了一下,看的源码版本是jdk1.8,以此做个记录

创建长整型的包装类Long的实例时,可以是

Long a = 100L;//自动装箱
Long b = Long.valueOf(100L);//静态方法
Long c = new Long(100L);//构造器

我们用“==”来判断一下几个对象

Long a = 100L;
Long b = Long.valueOf(100L);
Long c = new Long(100L);

System.out.println(a==b);//true
System.out.println(a==c);//false
System.out.println(b==c);//false

但是如果将100L修改为128L,结果却是

Long a = 128L;
Long b = Long.valueOf(128L);
Long c = new Long(128L);
        
System.out.println(a==b);//false
System.out.println(a==c);//false
System.out.println(b==c);//false

这里区别在于100L的时候a、b是同一个实例,而128L的时候a、b不是同一个实例,我们去翻一下Long的源码,找到这个valueOf方法

    public static Long valueOf(long l) {
        final int offset = 128;
        if (l >= -128 && l <= 127) { // will cache
            return LongCache.cache[(int)l + offset];
        }
        return new Long(l);
    }
    private static class LongCache {
        private LongCache(){}

        static final Long cache[] = new Long[-(-128) + 127 + 1];

        static {
            for(int i = 0; i < cache.length; i++)
                cache[i] = new Long(i - 128);
        }
    }

可见这里有这么一个static final的数组,是在静态代码块里初试化的,如果这个数字的范围是在-128——127之间,就不会调用构造器,而是返回这个数组里的对象,所以得到的会是同一个对象,“==”结果为true。

 

对于Integer类,也有类似的做法,也看一下valueOf 这部分的源码

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

不同的是Integer缓存的下界是-128,上界是可以通过jvm参数-XX:AutoBoxCacheMax=size指定,取指定值与127的最大值并且不超过Integer表示范围,如不指定那就是127了。

JDK的设计上有很多细节,也可以理解为很多坑,如果没有仔细的研究过你正在使用的JDK类的话,可能很难理解你所遇到的问题,致自己。

<think>嗯,用户现在明确想了解JDK源码的推荐阅读顺序,而且特别强调要参考站内已有的引用内容。看来用户是个有系统学习计划的Java开发者,可能正在搭建自己的源码学习体系。 从用户引用的材料来看,[^4]直接提供了JDK源码阅读顺序的优先级列表,这是最核心的参考。不过需要帮用户梳理得更系统些。用户之前问过Java优秀源码学习规划,这次聚焦在JDK上,说明ta正在按计划推进学习。 用户引用的[^2]提到搭建学习环境很重要,这个虽然不在当前问题范围内,但可以在回答中适当关联。另外[^1]和[^3]都强调理解设计模式和动手实践的价值,这些也应该融入阅读建议中。 注意到用户引用材料里有些细节值得展开: - [^4]的优先级列表虽然完整,但可以按功能模块重组,比如把java.lang包的核心类单独说明 - Thread和ThreadLocal优先级都是2,但并发包应该整体考虑 - 异常体系的Throwable/Error/Exception是递进关系,需要串联阅读 用户可能没明说但隐含的需求是:既想要具体类名的阅读顺序,又希望理解这样安排的理由。所以回答要兼顾实用性和理论依据。 专业层面需要补充的是: 1. 阅读JDK源码时结合《Effective Java》的实践建议(如Item 10关于重写equals的说明对应Object类源码) 2. 解释为什么String相关类要优先阅读(涉及不可变性、JVM优化等高频面试点) 3. 说明JUC包(java.util.concurrent)虽然不在[^4]列表里,但应是并发专题的重点 最后考虑设计成阶梯式学习路径,分基础/进阶/高级三个阶段,这样比单纯罗列类名更有操作性。每个阶段标注时间投入和产出预期,用户执行起来会更清晰。</think>基于您提供的引用资料和JDK源码学习特点,我为您整理出系统性学习顺序,兼顾核心类优先级知识关联性: ### 一、JDK源码阅读顺序(优先级+模块化) ```mermaid graph TD A[java.lang包] --> B(Object) B --> C(String/AbstractStringBuilder) C --> D(StringBuffer/StringBuilder) A --> E(基本类型包装类) E --> F(Integer/Long) F --> G(Boolean/Byte等) A --> H(并发基础) H --> I(Thread) H --> J(ThreadLocal) K[java.util包] --> L(集合框架) L --> M(ArrayList/HashMap) L --> N(LinkedList/TreeMap) O[异常体系] --> P(Throwable) P --> Q(Error/Exception) R[高级主题] --> S(Class/ClassLoader) R --> T(并发JUC包) ``` #### 阶段1:核心基础(1-2个月) **优先级1**(必读类目): 1. `java.lang.Object` - 所有类的基类,掌握`hashCode()`、`equals()`、`notify()`/`wait()`等核心方法实现[^1][^4] - **关联知识**:对象头结构、monitor锁机制(结合《深入理解Java虚拟机》) 2. `java.lang.String` + `AbstractStringBuilder` - 分析不可变性设计、字符串池优化[^4] - **延伸阅读**:`StringBuffer`(线程安全) vs `StringBuilder`(非线程安全) 3. 基本类型包装类(重点阅读`Integer`) - 学习缓存机制(-128~127的IntegerCache) - 自动装箱拆箱原理(`valueOf()``intValue()`) #### 阶段2:关键机制(1个月) **优先级2**: 4. `java.lang.Thread` - 线程状态机(`NEW/RUNNABLE/BLOCKED`等)`start()`/`run()`执行流程 - **调试技巧**:用IDEA跟踪线程调度过程[^2] 5. `java.lang.ThreadLocal` - 理解ThreadLocalMap内存泄漏防范(弱引用使用) 6. 集合框架(按顺序阅读): ```markdown 1. ArrayList → 数组扩容机制(grow()方法) 2. HashMap → 哈希冲突解决、红黑树转换(JDK8优化) 3. LinkedList → 双向链表实现 4. TreeMap → 红黑树实战案例 ``` #### 阶段3:体系深入(1个月) **优先级3**: 7. `java.lang.Throwable` - 异常继承体系:`Error`(系统级错误) vs `Exception`(可处理异常) - 掌握`fillInStackTrace()`性能影响 8. `java.lang.Enum` - 枚举类编译后结构(反编译查看`values()`生成) #### 阶段4:高级模块(选读) **优先级4**: 9. `java.lang.Class` & `ClassLoader` - 类加载过程(加载→链接→初始化) - 双亲委派机制实现(`loadClass()`方法) 10. `java.util.concurrent`(JUC包) - 先读`ReentrantLock` → 再读`ConcurrentHashMap` → 最后读线程池(`ThreadPoolExecutor`) ### 二、高效学习策略 1. **环境搭建**(引用[^2]实践) ```bash # Maven项目配置(pom.xml) <dependencies> <dependency> <groupId>jdk.tools</groupId> <artifactId>jdk.tools</artifactId> <version>1.8</version> <scope>system</scope> <systemPath>${java.home}/../lib/tools.jar</systemPath> </dependency> </dependencies> ``` - 使用IDEA关联JDK源码(Ctrl+点击直接跳转) 2. **阅读技巧** - 先读单元测试(如`java.util.CollectionsTest`) - 结合《Effective Java》[^3]分析设计决策(如Item 15: 最小化可变性) - 用UML绘制核心类关系图(推荐PlantUML) 3. **实践验证** ```java // 示例:验证String的hashCode缓存 String s = "hello"; Field hashField = String.class.getDeclaredField("hash"); hashField.setAccessible(true); System.out.println("Initial hash: " + hashField.get(s)); // -1表示未计算 s.hashCode(); System.out.println("Computed hash: " + hashField.get(s)); // 99162322 ``` ### 三、学习路线图 | 时间段 | 重点模块 | 产出物示例 | |----------|-------------------|---------------------------| | 第1-2周 | Object/String | 手写equals()方法实现规范 | | 第3-4周 | 集合框架 | 对比ArrayListLinkedList性能报告 | | 第5周 | Thread/ThreadLocal| 线程上下文传递方案设计 | | 第6-8周 | JUC包 | 实现自定义线程池 | > **关键提示**:阅读时重点关注`@since`标签(如`HashMap`在JDK8的红黑树优化),结合[OpenJDK官网](https://openjdk.org/)查阅变更历史[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值