Java包装类缓存机制

简介: 首先,来看一道常见的面试题,下面代码运行后会输出什么?

网络异常,图片无法展示
|


面试题


首先,来看一道常见的面试题,下面代码运行后会输出什么?

网络异常,图片无法展示
|

上面代码运行后,最终会输出falsetrue;为什么会这样呢?

按道理来说,在Java中==是比较两个对象的地址,上面代码中i3i4是两个不同的对象,理应也应该返回是false,怎么返回是true呢?让我们慢慢往下看

Integer的缓存机制

让我们来看看他的源代码.

当执行Integer i=128;这个语句时,Java会调用valueOf(int i)方法,然后自动装箱的方式,让其变成Integer i=new Integer(128),具体源码如下:

public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    //装箱
    return new Integer(i);
}

从上面的源码中可以看到,在装箱之前会执行一个if语句,这个if语句就是判断传入的值是否在缓存内,如果在缓存内,就直接返回缓存内的值,如果不在缓存内,就装箱,在堆内创建一个新空间来存放.

//Integer包装类缓存源码
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~127,所以过程大致如下:

网络异常,图片无法展示
|

按照上面这个方法,只要在数据在缓存池范围内的,都会引用缓存在堆内的地址,所有上面的i3==i4会输出为true;而不在缓存范围内的,就会在堆中开放新的空间来存放对象,所以地址不同,用==比较返回也不同;

其他包装类缓存机制

除了Integer之外,其他的包装类也使用了缓存技术;

Long

缓存范围-128~127

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

Byte

缓存范围-128127 (byte范围:一个byte占8位,所以取值范围是**-2^72^7-1**)

public static Byte valueOf(byte b) {
    final int offset = 128;
    return ByteCache.cache[(int)b + offset];
}
private static class ByteCache {
    private ByteCache(){}
    static final Byte cache[] = new Byte[-(-128) + 127 + 1];
    static {
        for(int i = 0; i < cache.length; i++)
            cache[i] = new Byte((byte)(i - 128));
    }
}

Character

缓存范围0~127 (ascii码范围)

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

Short

缓存范围-128~127

public static Short valueOf(short s) {
    final int offset = 128;
    int sAsInt = s;
    if (sAsInt >= -128 && sAsInt <= 127) { // must cache
        return ShortCache.cache[sAsInt + offset];
    }
    return new Short(s);
}
private static class ShortCache {
    private ShortCache(){}
    static final Short cache[] = new Short[-(-128) + 127 + 1];
    static {
        for(int i = 0; i < cache.length; i++)
            cache[i] = new Short((short)(i - 128));
    }
}

Boolean

缓存范围 truefalse 它只设置了两个静态变量用来充当缓存

public static final Boolean TRUE = new Boolean(true);
public static final Boolean FALSE = new Boolean(false);
public static Boolean valueOf(boolean b) {
    return (b ? TRUE : FALSE);
}

建议

包装类对比数据是否相同的时候,建议采用重写的equals()方法.

目录
相关文章
|
4天前
|
Java 开发者
深入理解Java中的异常处理机制
【9月更文挑战第6天】在Java编程的世界中,异常处理是一块不可或缺的拼图。就像我们在生活中遇到意外时需要冷静思考解决方案一样,Java程序也需要通过异常处理来应对运行时出现的问题。本文将引导你了解Java异常处理的核心概念,并教你如何巧妙地使用try-catch语句和finally块来捕获和处理异常。
13 2
|
12天前
|
消息中间件 算法 Java
深入浅出操作系统:进程管理的艺术掌握Java中的异常处理机制
【8月更文挑战第30天】在数字世界的舞台上,操作系统扮演着导演的角色,精心安排着每一个进程的表演。本文将揭开进程管理的神秘面纱,从进程的诞生到终结,探究它们如何在操作系统的指挥下和谐共舞。通过生动的比喻和直观的代码示例,我们将一同走进操作系统的核心,理解进程调度、同步与通信的内在机制,以及它们对计算生态的重要性。让我们跟随代码的节奏,一起感受操作系统的魅力吧!
|
11天前
|
存储 Java 测试技术
Java零基础教学(10):包装类
【9月更文挑战第1天】Java零基础教学篇,手把手实践教学!
16 1
|
13天前
|
Java 编译器 开发者
Java中的异常处理机制
【8月更文挑战第30天】在Java编程中,异常处理是不可或缺的一部分。本文将探讨Java的异常处理机制,包括异常的概念、分类以及如何处理异常。我们将通过实际代码示例来展示如何在Java程序中捕获和处理异常,确保程序的稳定性和可靠性。无论你是初学者还是有经验的开发者,这篇文章都将帮助你更好地理解和应用Java的异常处理机制。
11 1
|
9天前
|
安全 Java API
Java线程池原理与锁机制分析
综上所述,Java线程池和锁机制是并发编程中极其重要的两个部分。线程池主要用于管理线程的生命周期和执行并发任务,而锁机制则用于保障线程安全和防止数据的并发错误。它们深入地结合在一起,成为Java高效并发编程实践中的关键要素。
8 0
|
11天前
|
Java 开发者
Java编程中的异常处理机制探究
【8月更文挑战第31天】在Java的世界中,异常处理是维护程序稳定性的重要工具。它像是一套精密的免疫系统,保护代码免受错误的侵袭,确保程序能够优雅地应对意外情况。本文将带你走进Java的异常处理机制,了解如何捕获和处理异常,以及自定义异常类的创建与应用,让你的代码更加健壮,运行更加顺畅。
|
11天前
|
开发者 C# 自然语言处理
WPF开发者必读:掌握多语言应用程序开发秘籍,带你玩转WPF国际化支持!
【8月更文挑战第31天】随着全球化的加速,开发多语言应用程序成为趋势。WPF作为一种强大的图形界面技术,提供了优秀的国际化支持,包括资源文件存储、本地化处理及用户界面元素本地化。本文将介绍WPF国际化的实现方法,通过示例代码展示如何创建和绑定资源文件,并设置应用程序语言环境,帮助开发者轻松实现多语言应用开发,满足不同地区用户的需求。
22 0
|
11天前
|
Java 开发者
Java编程中的异常处理机制探究
【8月更文挑战第31天】 在Java的世界中,异常处理是维护程序稳定性的重要工具。它像是一套精密的免疫系统,保护代码免受错误的侵袭,确保程序能够优雅地应对意外情况。本文将带你走进Java的异常处理机制,了解如何捕获和处理异常,以及自定义异常类的创建与应用,让你的代码更加健壮,运行更加顺畅。
|
11天前
|
Java 程序员 开发者
深入理解Java中的异常处理机制
【8月更文挑战第31天】 本文旨在通过浅显易懂的方式,带你走进Java的异常世界。我们将从异常的基本概念出发,逐步深入到异常的分类、捕获和处理,最后通过代码示例来巩固你的理解。无论你是初学者还是有一定编程经验的开发者,这篇文章都将为你提供有价值的参考。
|
11天前
|
Java 程序员
深入浅出Java异常处理机制
【8月更文挑战第31天】本文旨在以浅显易懂的语言,为读者揭示Java异常处理的神秘面纱。通过日常生活中的小故事,我们将一步步走进异常的世界,探索它们的起源、分类以及如何妥善处理这些不请自来的特殊“客人”。文章中将穿插实际代码案例,帮助读者从理论到实践,全面掌握Java异常处理技巧。