跳至主要內容

包装类

荒流2020年8月5日大约 4 分钟约 1320 字

Java提供的8种基本数据类型不支持面向对象的编程机制,因此,Java为它们提供了包装类(wrapper class),为这8种基本数据类型分别定义了相应的引用类型。

基本数据类型包装类
byteByte
shortShort
intInteger
longLong
charCharacter
floatFloat
doubleDouble
booleanBoolean

包装类是不可变的,即一旦构造了包装器,就不允许更改包装在其中的值。同时,包装器类还是final的,因此不能派生它们的子类。

1. 自动装箱与自动拆箱

为了方便包装类的使用,JDK1.5 开始提供了自动装箱和自动拆箱的功能。

public class AutoBoxingUnboxing {
    public static void main(String[] args) {
        // 直接把一个基本类型变量赋给Integer对象
        Integer inObj = 5;
        // 直接把一个boolean类型变量赋给一个Object类型的变量
        Object boolObj = true;
        // 直接把一个Integer对象赋给int类型的变量
        int it = inObj;
        if (boolobj instanceof Boolean) {
            // 先把Object对象强制类型转换为Boolean类型,再赋给boolean变量
            boolean b = (Boolean)boolObj;
            System.out.println(b);
        }
    }
}

由于每个值分别包装在对象中,所以ArrayList<Integer>的效率远远低于int[]数组。

自动装箱规范要求booleanbytechar不超过 127,介于 -128 和 127 之间的 shortint 被包装到固定的对象中。

最后强调一下,装箱和拆箱是编译器要做的工作,而不是虚拟机。

从字节码中可知,装箱过程是通过调用包装器的 valueOf 方法实现的,而拆箱过程是通过调用包装器的 xxxValue 方法实现的。

2. 包装类的比较

2.1 包装类实例与基本数值类型的比较

虽然包装类型的变量是引用数据类型,但包装类的实例可以与数值类型的值进行比较,这种比较是直接取出包装类实例所包装的数值来进行的。

Integer a = Integer.valueOf(6);
// 输出true
System.out.println(a > 5.0);

2.2 两个包装类实例之间的比较

注意,若两个包装类的实例进行比较,由于包装类的实例实际上是引用类型,因此只有两个包装类引用指向同一个对象时才会返回true

System.out.println(Integer.valueOf(128) == Integer.valueOf(128)); // false

2.3 特殊情况——缓存

特殊地, 由于java.lang.Integer源码中对-128~127的整数自动装箱为Integer实例,并放入一个cache数组缓存起来, 以下输出为 true

System.out.println(Integer.valueOf(127) == Integer.valueOf(127)); // true

2.4 包装类的静态方法compare(Xxx val1, Xxx val2)

Java还为所有的包装类提供了一个静态的compare(xxx val1, xxx val2)方法,可以用来比较两个基本类型值的大小,包括比较两个boolean类型值(此时true > false)

System.out.println(Boolean.compare(true, false));  //输出1
System.out.println(Boolean.compare(true, true));  //输出0
System.out.println(Boolean.compare(false, true));  //输出-1

3. 基本类型变量与字符串之间的转换

字符串类型的值->基本类型的值:

  1. 利用包装类提供的parseXxx(String s)静态方法(除Character外所有包装类都提供该方法)

  2. 利用包装类提供的valueOf(String s)静态方法

基本类型的值->字符串类型的值:

  1. String类提供了多个重载valueOf()方法,用于将基本类型变量转换成字符串
  2. 将基本类型变量和""进行连接运算,系统会自动把基本类型变量转换成字符串
public class Primitive2String {
    public static void main(String[] args) {
        String intStr = "123";

        // 把一个特定字符串转换成int变量
        int it1 = Integer.parseInt(intStr);
        int it2 = Integer.valueOf(intStr);
        System.out.println(it2);
        String floatStr = "4.56";

        // 把一个特定字符串转换成float变量
        float ft1 = Float.parseFloat(floatStr);
        float ft2 = Float.valueOf(floatStr);
        System.out.println(ft2);

        // 把一个float变量转换成String变量
        String ftStr = String.valueOf(2.345f);
        System.out.println(ftStr);

        // 把一个double变量转换成String变量
        String dbStr = String.valueOf(3.344);
        System.out.println(dbStr);

        // 把一个boolean变量转换成String变量
        String boolStr = String.valueOf(true);
        System.out.println(boolStr.toUpperCase());
    }
}

4. Java8的增强

Java 8再次增强了包装类的功能,其中之一是支持无符号算术运算

  1. 为整型包装类Integer, Long提供的无符号运算支持:
    • static String toUnsignedString(int/long i)
    • static String toUnsignedString(int/long i, int radix):radix指定进制
    • static xxx parseUnsignedXxx(String s):将字符串解析成无符号整数。
    • static xxx parseUnsignedXxx(String s, int radix)
    • static int compareUnsigned(xxx x, xxx y):将x、y两个整数转换为无符号整数后比较大小。
      • 当调用类为Integer时,xxx代表int
      • 当调用类为Long时,xxx代表long
    • static long divideUnsigned(long dividend, long divisor):将x、y转换为无符号整数后计算它们相除的商。
    • static long remainderUnsigned(long dividend, long divisor):将x、y转换为无符号整数后计算它们相除的余数。
  2. Byte, Short提供了toUnsignedInt(xxx x), toUnsignedLong(yyy x)两个方法,用于将指定byteshort类型的变量或值转换成无符号的intlong