java 基础数据类型和包装类的本质区别

320 阅读2分钟

Java 基础数据类型和包装类的本质区别主要在于以下几个方面:

  1. 存储位置:基础数据类型存储在栈内存中,而包装类对象存储在堆内存中。
  2. 值与对象:基础数据类型直接存储的是值,而包装类是对象,封装了对应的基础数据类型的值。
  3. 默认值:基础数据类型有其自身特定的默认值(如int的默认值为0),而包装类的默认值是null。
  4. 操作方式:基础数据类型可以直接进行算术运算、比较等操作,而包装类则需要通过方法调用来完成这些操作。

下面让我们通过源码分析更详细地了解这些区别。

基础数据类型

Java 中的八种基础数据类型分别是:

  • byte
  • short
  • int
  • long
  • float
  • double
  • char
  • boolean

这些类型在内存中直接存储相应的数值。例如,int 类型的变量直接存储一个32位的整数。

包装类

每种基础数据类型都有一个相应的包装类,这些包装类都位于 java.lang 包中:

  • Byte
  • Short
  • Integer
  • Long
  • Float
  • Double
  • Character
  • Boolean

Integer 类为例,我们通过源码来看看它的实现:

public final class Integer extends Number implements Comparable<Integer> {
    private final int value;

    public Integer(int value) {
        this.value = value;
    }

    public int intValue() {
        return value;
    }
    
    // 其他方法,如compareTo, equals, hashCode等
}

Integer 类的源码可以看到,它内部包含了一个 int 类型的字段 value,用于存储实际的整数值。包装类不仅仅是将基础数据类型封装成对象,还提供了一些额外的方法,例如 Integer 类中的 parseInt 方法、valueOf 方法等。

自动装箱和拆箱

Java 提供了自动装箱(Autoboxing)和拆箱(Unboxing)的机制,使得基础数据类型和其相应的包装类之间可以自动转换:

int primitiveInt = 5;
Integer wrappedInt = primitiveInt; // 自动装箱
int newPrimitiveInt = wrappedInt;  // 自动拆箱

自动装箱源码分析

当执行 Integer wrappedInt = primitiveInt; 时,实际上是调用了 Integer.valueOf 方法:

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

这个方法会检查是否在缓存范围内,如果是,则从缓存中返回相应的 Integer 对象,否则创建一个新的 Integer 对象。

自动拆箱源码分析

当执行 int newPrimitiveInt = wrappedInt; 时,实际上是调用了 intValue 方法:

public int intValue() {
    return value;
}

这个方法直接返回内部存储的 int 值。

总结

  • 基础数据类型:直接存储值,位于栈内存,操作简单高效。
  • 包装类:对象形式,存储在堆内存,提供了更多的方法和功能,支持自动装箱和拆箱。