Loading

包装类

基本数据类型的包装类

我们前面学习的八种基本数据类型并不是对象,为了将基本类型数据和对象之间实现互相转化,Java 为每一个基本数据类型提供了相应的包装类。

包装类基本知识

Java 是面向对象的语言,但并不是“纯面向对象”的,因为我们经常用到的基本数据类型就不是对象。但是我们在实际应用中经常需要将基本数据转化成对象,以便于操作。比如:将基本数据类型存储到 Object[ ]数组或集合中的操作等等。为了解决这个不足,Java 在设计类时为每个基本数据类型设计了一个对应的类进行代表,这样八个和基本数据类型对应的类统称为包装类(Wrapper Class)。

包装类位于 java.lang 包,八种包装类和基本数据类型的对应关系:

在这八个类名中,除了 Integer 和 Character 类以外,其它六个类的类名和基本数据类型一致,只是类名的第一个字母大写而已。

Number 类是抽象类,因此它的抽象方法,所有子类都需要提供实现。Number 类提供了抽象方法:intValue()、longValue()、floatValue()、doubleValue(),意味着所有的“数
字型”包装类都可以互相转型。

下面我们通过一个简单的示例认识一下包装类。

【示例】初识包装类

public class WrapperClassTest {
    public static void main(String[] args) {
        Integer i = new Integer(10); //从 java9 开始被废弃
        Integer j = Integer.valueOf(50); //官方推荐
    }
}

示例内存分析如图所示:

包装类的用途

对于包装类来说,这些类的用途主要包含两种:

  1. 作为和基本数据类型对应的类型存在,方便涉及到对象的操作,如 Object[ ]、集合等的操作。
  2. 包含每种基本数据类型的相关属性如最大值、最小值等,以及相关的操作方法(这些操作方法的作用是在基本数据类型、包装类对象、字符串之间提供相互之间的转化!)。

【示例】包装类的使用

public class Test {
    /** 测试 Integer 的用法,其他包装类与 Integer 类似 */
    void testInteger() {
        // 基本类型转化成 Integer 对象
        Integer int1 = new Integer(10); //已经被废弃,不推荐使用
        Integer int2 = Integer.valueOf(20); // 官方推荐这种写法
        // Integer 对象转化成 int
        int a = int1.intValue();
        // 字符串转化成 Integer 对象
        Integer int3 = Integer.parseInt("334");
        Integer int4 = new Integer("999");
        // Integer 对象转化成字符串
        String str1 = int3.toString();
        // 一些常见 int 类型相关的常量
        System.out.println("int 能表示的最大整数:" + Integer.MAX_VALUE);
    }
    public static void main(String[] args) {
        Test test = new Test();
        test.testInteger();
    }
}

执行结果如图所示:

自动装箱和拆箱

自动装箱(autoboxing)和拆箱(unboxing):将基本数据类型和包装类自动转换。

自动装箱:

基本类型的数据处于需要对象的环境中时,会自动转为“对象”。
我们以 Integer 为例:
Integer i = 5
编译器会自动转成:Integer i = Integer.valueOf(5),这就是 Java 的自动装箱。

自动拆箱:

每当需要一个值时,对象会自动转成基本数据类型,没必要再去显式调用 intValue()、
doubleValue()等转型方法。
Integer i = Integer.valueOf(5);
int j = i;
编译器会自动转成:int j = i.intValue();
这样的过程就是自动拆箱。

自动装箱/拆箱的本质是:

自动装箱与拆箱的功能是编译器来帮忙,编译器在编译时依据您所编写的语法,决定是
否进行装箱或拆箱动作。

【示例】自动装箱

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

【示例】自动拆箱

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

自动装箱与拆箱的功能是所谓的“编译器蜜糖(Compiler Sugar)”,虽然使用这个功能很方
便,但在程序运行阶段您得了解 Java 的语义。如下所示的程序是可以通过编译的:

【示例】包装类空指针异常问题

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

执行结果如图所示:

运行结果之所以会出现空指针异常,是因为如上代码相当于:

public class Test1 {
    public static void main(String[] args) {
        /*示例的代码在编译时期是合法的,但是在运行时期会有错误
        因为其相当于下面两行代码*/
        Integer i = null;
        int j = i.intValue();
    }
}

包装类的缓存问题

整型、char类型所对应的包装类,在自动装箱时,对于-128127之间的值会进行缓存处理,其目的是提高效率。缓存原理为:如果数据在-128127这个区间,那么在类加载时就已经为该区间的每个数值创建了对象,并将这256个对象存放到一个名为cache的数组中。每当自动装箱过程发生时(或者手动调用valueOf()时),就会先判断数据是否在该区间,如果在则直接获取数组中对应的包装类对象的引用,如果不在该区间,则会通过new调用包装类的构造方法来创建对象。

总结

  • 自动装箱调用的是 valueOf()方法,而不是 new Integer()方法。
  • 自动拆箱调用的 xxxValue()方法。
  • 包装类在自动装箱时为了提高效率,对于-128~127 之间的值会进行缓存处理。超过范围后,对象之间不能再使用==进行数值的比较,而是使用 equals 方法。
posted @ 2022-12-13 16:07  听风blog  阅读(73)  评论(0编辑  收藏  举报