Java 自动装箱和拆箱还有包装类的缓存问题

自动装箱和拆箱就是将基本数据类型和包装类之间进行自动的互相转换。JDK1.5 后,
Java 引入了自动装箱(autoboxing)/拆箱(unboxing)。

自动装箱:

基本类型的数据处于需要对象的环境中时,会自动转为"对象"。

我们以 Integer 为例:

在 JDK1.5 以前,这样的代码 Integer i = 5 是错误的,必须要通过 Integer i = new

Integer(5) 这样的语句来实现基本数据类型转换成包装类的过程;

而在 JDK1.5 以后,Java 提供了自动装箱的功能,因此只需 Integer i = 5 这样的语句

就能实现基本数据类型转换成包装类,这是因为 JVM 为我们执行了 Integer i =

Integer.valueOf(5)这样的操作,这就是 Java 的自动装箱。
自动拆箱:

每当需要一个值时,对象会自动转成基本数据类型,没必要再去显式调用 intValue()、

doubleValue()等转型方法。

如 Integer i = 5;int j = i; 这样的过程就是自动拆箱。

我们可以用一句话总结自动装箱/拆箱:

自动装箱过程是通过调用包装类的 valueOf()方法实现的,而自动拆箱过程是通过调用

包装类的 xxxValue()方法实现的(xxx 代表对应的基本数据类型,如 intValue()、

doubleValue()等)。

自动装箱与拆箱的功能事实上是编译器来帮的忙,编译器在编译时依据您所编写的语

法,决定是否进行装箱或拆箱动作。

自动装箱:

java 复制代码
Integer i = 100;//自动装箱
//相当于编译器自动为您作以下的语法编译:
Integer i = Integer. valueOf (100);//调用的是 valueOf(100),而不是 new Integer(100)

自动拆箱:

java 复制代码
Integer i = 100;
int j = i;//自动拆箱
//相当于编译器自动为您作以下的语法编译:
int j = i.intValue();

所以自动装箱与拆箱的功能是所谓的"编译器蜜糖(Compiler Sugar)",虽然使用这

个功能很方便,但在程序运行阶段您得了解 Java 的语义:

包装类空指针异常问题:

java 复制代码
public class Test1 {
    public static void main(String[ ] args) {
        Integer i = null;
        int j = i;
    }
}

null 表示 i 没有指向任何对象的实体,但作为对象名称是合法的(不管这个对象名称存

是否指向了某个对象的实体)。由于实际上 i 并没有指向任何对象的实体,所以也就不可能

操作 intValue()方法,这样上面的写法在运行时就会出现 NullPointerException 错误。

包装类的缓存问题:

整型、char类型所对应的包装类,在自动装箱时,对于-128~127之间的值会进行缓存

处理,其目的是提高效率。

缓存处理的原理为:如果数据在-128~127这个区间,那么在类加载时就已经为该区间

的每个数值创建了对象,并将这256个对象存放到一个名为cache的数组中。每当自动装箱

过程发生时(或者手动调用valueOf()时),就会先判断数据是否在该区间,如果在则直接

获取数组中对应的包装类对象的引用,如果不在该区间,则会通过new调用包装类的构造方法来创建对象。

下面我们以Integer类为例,看一看Java为我们提供的源码,加深对缓存技术的理解:

java 复制代码
public static Integer valueOf(int i) {
if (i >= IntegerCache. low && i <= IntegerCache. high )
return IntegerCache. cache [i + (-IntegerCache. low )];
return new Integer(i);
}

这段代码中我们需要解释下面几个问题:

  1. IntegerCache类为Integer类的一个静态内部类,仅供Integer类使用。

  2. 一般情况下 IntegerCache.low为-128,IntegerCache.high为127,

IntegerCache.cache为内部类的一个静态属性:

java 复制代码
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() {}
}

由上面的源码我们可以看到,静态代码块的目的就是初始化数组cache的,这个过程会

在类加载时完成。

下面我们做一下代码测试

包装类的缓存测试:

java 复制代码
public class Test3 {
    public static void main(String[ ] args) {
        Integer in1 = -128;
        Integer in2 = -128;
        System. out .println(in1 == in2);//true 因为 123 在缓存范围内
        System. out .println(in1.equals(in2));//true
        Integer in3 = 1234;
        Integer in4 = 1234;
        System. out .println(in3 == in4);//false 因为 1234 不在缓存范围内
        System. out .println(in3.equals(in4));//true

执行后的结果:

如下是Test3的内存分析:

相关推荐
future141238 分钟前
C#每日学习日记
java·学习·c#
abigalexy41 分钟前
深入JVM底层-垃圾回收GC算法
jvm
coding随想42 分钟前
JavaScript中的BOM:Window对象全解析
开发语言·javascript·ecmascript
一个混子程序员43 分钟前
SpringBoot自定义Schedule注解
java
心之语歌1 小时前
Java高效压缩技巧:ZipOutputStream详解
java·后端
booooooty1 小时前
基于Spring AI Alibaba的多智能体RAG应用
java·人工智能·spring·多智能体·rag·spring ai·ai alibaba
猴哥源码1 小时前
基于Java+SpringBoot的健身房管理系统
java·spring boot
极光雨雨1 小时前
Spring Bean 控制销毁顺序的方法总结
java·spring
猴哥源码1 小时前
基于Java+SpringBoot的三国之家网站
java·spring boot
念九_ysl1 小时前
Java 使用 OpenHTMLToPDF + Batik 将含 SVG 遮罩的 HTML 转为 PDF 的完整实践
java·开发语言·pdf