跳到主要内容

Java 中的包装类

Java 中的包装类是一组特殊的类,它们为 Java 的八个基本数据类型提供了对象表示。由于基本数据类型不是对象,当需要对象表示时,例如在集合框架或某些方法参数中,我们使用相应的包装类。

以下是基本数据类型及其对应的包装类:

byte -> Byte
short -> Short
int -> Integer
long -> Long
float -> Float
double -> Double
char -> Character
boolean -> Boolean

包装类的主要用途

包装类将基本数据类型的值对象化,方便调用所需的方法和属性。这些类还提供了类型转换的功能,允许在不同数据类型之间进行转换。由于 Java 的集合框架只支持存储对象类型,包装类使得基本类型的数据能够被集合存储。此外,包装类本身包含一些静态方法,可以正确支持对数据的处理。

例如,Integer类提供了将十进制数转换为二进制字符串的方法,还可以将字符串解析为整数。这些方法在数据处理和转换中非常实用。

包装类的示例代码

package com.wrapper_class;

public class Test {
public static void main(String[] args) {
// 包装类的静态方法示例
// 十进制转二进制
String binaryString = Integer.toString(100, 2);
System.out.println(binaryString); // 输出: 1100100

// 二进制转十进制
int decimal = Integer.parseInt("100", 2);
System.out.println(decimal); // 输出: 4

// 自动装箱:将基本类型转换为包装类对象
Integer num1 = 1;
Integer num2 = 1;
System.out.println(num1 == num2); // 输出: true 相同引用

// 手动装箱:使用构造方法创建对象
Integer num3 = new Integer(2);
Integer num4 = new Integer(2);
System.out.println(num3 == num4); // 输出: false 不同引用
System.out.println(num3.equals(num4)); // 输出: true 值相等

// 自动装箱超出缓存范围
Integer num5 = 128;
Integer num6 = 128;
System.out.println(num5 == num6); // 输出: false 不同引用

/*
* 自动装箱的实现原理
* 自动装箱调用了Integer.valueOf方法
* IntegerCache.low = -128
* IntegerCache.high = 127
* 因此,-128到127之间的数在自动装箱时会从缓存中获取
* 这样做是为了优化常用数字的性能和内存使用效率
*/
Integer num7 = Integer.valueOf(127);
Integer num8 = Integer.valueOf(127);
Integer num9 = Integer.valueOf(1);
Integer num10 = Integer.valueOf(1);
System.out.println(num7 == num8); // 输出: true
System.out.println(num9 == num10); // 输出: true

// 以下是Integer.valueOf方法的简化实现
// public static Integer valueOf(int i) {
// if (i >= Integer.IntegerCache.low && i <= Integer.IntegerCache.high)
// return Integer.IntegerCache.cache[i + (-Integer.IntegerCache.low)];
// return new Integer(i);
// }
}
}

拆箱与装箱

装箱是指将基本数据类型转换为其对应的包装类对象,而拆箱则是将包装类对象转换回基本数据类型。自 JDK 1.5 起,Java 引入了自动装箱和自动拆箱功能,简化了基本类型与包装类之间的转换。

例如:

package com.wrapper_class;

public class Test2 {
public static void main(String[] args) {
// 自动装箱:将基本类型转换为包装类对象
Integer number = 996;
// 在打印时,会调用Integer的toString方法
System.out.println(number); // 输出: 996
System.out.println(number instanceof Integer); // 输出: true

// 手动拆箱:将包装类对象转换为基本类型
int primitive = number.intValue();
System.out.println(primitive); // 输出: 996
// 拆箱后的primitive是基本数据类型,无法调用Integer的方法
}
}

注意事项

缓存机制:Java 对某些数值范围的包装类对象进行了缓存,例如Integer类缓存了-128 到 127 之间的整数。这意味着在这个范围内,自动装箱的对象引用相同,==比较为true。超出这个范围时,每次装箱都会创建新的对象。

性能考虑:虽然包装类提供了丰富的功能,但频繁使用装箱和拆箱可能会影响性能。在性能敏感的场景下,尽量使用基本数据类型。

不可变性:包装类是不可变的,一旦创建,其值不可更改。这有助于提高线程安全性,但需要注意在需要可变数据类型时的选择。

空指针异常:包装类对象可以为null,在进行拆箱操作时,如果对象为null,会抛出NullPointerException。因此,在使用包装类时应确保对象不为null

Integer 类默认缓存了-128 到 127 之间的整数,这个范围可以通过 JVM 参数 -XX:AutoBoxCacheMax=<size> 来修改上限。其他包装类如 Character 也有类似的缓存机制。