Java包装类

2021/01/02 Java基础知识 共 2139 字,约 7 分钟
闷骚的程序员

1. java 数据类型?

1.1 java中8大基本类型?

  1. 整型 byte;
  2. 整型 short;
  3. 整型 int;
  4. 整型 long;
  5. 浮点型 float;
  6. 双精度浮点型 double;
  7. 布尔型 boolean;
  8. 字符型 char;

1.2 java数据类型分类

  1. 基本数据类型(8大基本数据类型);
  2. 引用类型;
    引用类型具体划分为:
    接口 Interface;
    类 Class;
    枚举 Enum;
    数组 Array;
    注解 Annotation;

2. java 包装类?

2.1 什么是java中的包装类?

  1. java中存在8大基本数据类型,这8种基本数据类型本身存储的是值,并不是引用地址。
  2. 为了实现“处处皆对象”的理念,java对8大基本数据类型分别创造了对应的包装类。
    byte – Byte
    short – Short
    int – Integer
    long – Long
    float – Float
    double – Double
    boolean – Boolean
    char – Character

2.2 自动装箱和自动拆箱?

  1. jdk 5之前,不存在自动装箱和自动拆箱。说白了就是基本数据类型和对应的包装类型进行转换,需要手动转换。比如:
    int a = 10;
    // 手动将a装箱为Integer类型
    Integer b = new Integer(a); 
    // 同上,手动装箱
    Integer c = Integer.valueOf(a);
    // 将c手动拆箱转换为int类型
    int d = c.intValue(); 
    

    其他基本类型和包装类型的手动装箱、手动拆箱与Integer类似。

  2. jdk5之后,JVM提供了自动装箱和拆箱:
    // 将int类型的10自动装箱为Integer类型
    Integer b = 10; 
    // 将Integer类型的b自动拆箱为int类型
    int c = b; 
    
  3. 自动装箱和拆箱实际上就是对valueOf()方法和intValue()方法的默认调用。由此可见,当拆箱对象为null值时,自动拆箱相当于如下:
    Integer a = null;
    // a自动拆箱,相当于调用 a.intValue(),因此会报空指针异常。
    int b = a; 
    

2.3 包装类进行==比较的陷阱

以Integer为例,Integer实际上在比较时,两个Integer对象进行 == 比较,当Integer类型数据再 -128-127 之间时,会直接返回Integer内部的固定引用(Integer对象有个私有静态内部类IntegerCache,将 -128-127之间的数据提前实例化好缓存起来了)。因此当比较数据再该范围时,两个数值相同的Integer对象使用 == 比较的结果为true。
然而,一旦数值不在该范围,使用==比较的则是两个重新创建的Integer实例,因此即便数值相同,== 的比较结果也为false。

总结:

  1. 如果Integer的两个数在-128-127之间,则直接使用==比较相等(必要时进行判空)。
  2. 比较两个Integer数值,可以使用Integer内部的equals()方法(必要时进行判空),或者直接使用Objects.equals()方法进行比较,或者将两个对象分别通过intValue()方法拆箱为基本类型后再使用==进行比较。

2.4 建议使用Objects.equals进行比较两个值

当我们比较两个 Integer 类型的对象时,Objects.equals 源码确实会首先使用 == 运算符来比较。这时候,如果 Integer 的值超出了缓存范围(-128127),== 比较的是两个对象的内存地址,而不是值,可能会导致比较结果为 false

然而,深入分析 Objects.equals 的逻辑可以澄清这个问题:

Objects.equals 的完整逻辑

  1. Objects.equals(a, b) 首先检查 a == b
    • 如果 ab 是同一个对象(即内存地址相同),返回 true
    • 如果地址不同,则继续比较。
  2. 如果 anull,直接返回 false(因为此时 b 一定不为 null)。
  3. 调用 a.equals(b),进入 Integer.equals 方法:
    • Integer.equals 方法比较的是值,即 value == ((Integer) obj).intValue()

因此,即使 ab 的地址不同,只要它们的值相等,最终结果仍然是 true

验证示例

Integer a = 200; // 超出缓存范围
Integer b = 200; // 超出缓存范围

System.out.println(a == b); // false,因为地址不同
System.out.println(Objects.equals(a, b)); // true,因为最终调用了 equals

在这段代码中:

  • a == b 返回 false,因为两个对象是不同的实例。
  • Objects.equals(a, b) 返回 true,因为值相等。

关键点:为何 Objects.equals 安全?

  • 即使 == 比较不通过,Objects.equals 的逻辑会继续调用 a.equals(b) 来比较值。
  • Integer.equals 方法会比较实际的数值,而不是引用。

总结

虽然 Objects.equals 确实会先进行 == 比较,但如果两个 Integer 对象的地址不同,Objects.equals 仍会调用 equals 方法来比较它们的值。因此,在使用 Objects.equals 时,无需担心缓存范围问题,它始终能够正确比较 Integer 的值是否相等。

文档信息

Search

    Table of Contents