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的内存分析:

相关推荐
kobesdu1 小时前
【ROS2实战笔记-19】ROS2 生命周期节点的启动顺序、状态转换陷阱与热备方案
java·前端·笔记·机器人·ros·ros2
谙弆悕博士1 小时前
快速学C语言——第16章:预处理
c语言·开发语言·chrome·笔记·创业创新·预处理·业界资讯
neo_Ggx231 小时前
Maven 版本管理详解:SNAPSHOT、Release 与 Nexus 仓库的区别和影响
java·maven
matlabgoodboy1 小时前
软件开发定制小程序APP帮代做java代码代编写C语言设计python编程
java·c语言·小程序
江离w2 小时前
新版vibecoding项目初始化指令
java
yuan199972 小时前
基于 C# 实现的 Omron HostLink (FINS) 协议 PLC 通讯
开发语言·c#
tongluowan0072 小时前
Spring MVC 底层工作流程+源码分析
java·spring·mvc
qq_422828622 小时前
android图形学之SurfaceControl和Surface的关系 五
android·开发语言·python
weixin_444012932 小时前
c++如何将std--vector直接DUMP到二进制文件_指针地址直写【附代码】
jvm·数据库·python
woxihuan1234563 小时前
Go语言中--=运算符详解:位右移赋值操作的原理与应用
jvm·数据库·python