在 Java 中,包装类泛型是两个常见的概念,它们在日常开发中有广泛的应用。包装类用于将基本数据类型包装成对象,而泛型则提供了一种类型安全的方式来处理集合类型的元素。理解包装类和泛型的使用方式是掌握 Java 编程的关键。

1. Java 包装类

Java 的基本数据类型(如 intcharboolean 等)不是对象类型,而 Java 的对象通常需要继承 Object 类。因此,Java 提供了包装类(Wrapper Classes)来将基本类型转换成对象,包装类位于 java.lang 包中。每个基本数据类型都有对应的包装类:

  • byte 对应 Byte
  • short 对应 Short
  • int 对应 Integer
  • long 对应 Long
  • float 对应 Float
  • double 对应 Double
  • char 对应 Character
  • boolean 对应 Boolean

1.1 包装类的作用

包装类使得基本数据类型能够作为对象使用,提供了很多方便的功能,如:

  • 可以在泛型中使用(因为泛型不能直接使用基本数据类型)。
  • 提供了与基本类型相对应的许多方法,如 parseInt()valueOf() 等。

1.2 自动装箱与拆箱

Java 5 引入了自动装箱(Auto-boxing)和自动拆箱(Auto-unboxing),使得基本数据类型和包装类之间的转换变得更加便捷。自动装箱是指将基本数据类型自动转换为对应的包装类,而自动拆箱则是将包装类自动转换为基本数据类型。

示例:
public class WrapperExample {
    public static void main(String[] args) {
        // 自动装箱:基本数据类型转换为包装类
        Integer intObject = 10;  // 相当于 Integer intObject = Integer.valueOf(10);

        // 自动拆箱:包装类转换为基本数据类型
        int intValue = intObject;  // 相当于 int intValue = intObject.intValue();

        System.out.println("intObject = " + intObject); // 输出:intObject = 10
        System.out.println("intValue = " + intValue);   // 输出:intValue = 10
    }
}

2. Java 泛型

泛型(Generics)是 Java 5 引入的一个强大的特性,主要用于在编译时就确定类型,增强类型安全性,并避免了类型转换的麻烦。泛型使得你可以编写更通用的代码,同时保证类型安全。

2.1 泛型的基本语法

泛型通常在类、接口、方法的声明中使用,允许类和方法在定义时不指定具体的类型,而是使用类型参数。在实际使用时,可以为这些类型参数指定具体的类型。

示例:泛型类
public class Box<T> {
    private T value;

    public T getValue() {
        return value;
    }

    public void setValue(T value) {
        this.value = value;
    }
}

public class GenericExample {
    public static void main(String[] args) {
        Box<Integer> integerBox = new Box<>();
        integerBox.setValue(10);  // 设置值为 Integer 类型
        System.out.println("Integer Value: " + integerBox.getValue());  // 输出:10

        Box<String> stringBox = new Box<>();
        stringBox.setValue("Hello Generics");
        System.out.println("String Value: " + stringBox.getValue());  // 输出:Hello Generics
    }
}

2.2 泛型方法

除了泛型类,Java 还允许方法使用泛型。在方法级别使用泛型,可以使方法更加灵活。

示例:泛型方法
public class GenericMethodExample {
    // 泛型方法
    public static <T> void printArray(T[] array) {
        for (T element : array) {
            System.out.print(element + " ");
        }
        System.out.println();
    }

    public static void main(String[] args) {
        Integer[] intArray = {1, 2, 3, 4, 5};
        String[] strArray = {"Hello", "World", "Generics"};

        printArray(intArray);  // 输出:1 2 3 4 5
        printArray(strArray);  // 输出:Hello World Generics
    }
}

2.3 泛型通配符(Wildcards)

泛型通配符允许你定义泛型类型的范围,使用 ? 来表示任意类型。常见的通配符有:

  • ? extends T:表示 T 或其子类。
  • ? super T:表示 T 或其父类。
  • ?:表示任意类型。
示例:通配符使用
import java.util.*;

public class WildcardExample {
    // 使用 extends 通配符
    public static void printList(List<? extends Number> list) {
        for (Number num : list) {
            System.out.println(num);
        }
    }

    public static void main(String[] args) {
        List<Integer> intList = Arrays.asList(1, 2, 3);
        List<Double> doubleList = Arrays.asList(1.1, 2.2, 3.3);
        
        printList(intList);  // 输出:1 2 3
        printList(doubleList);  // 输出:1.1 2.2 3.3
    }
}

2.4 泛型与包装类的结合

泛型通常要求使用对象类型,基本数据类型不能直接用于泛型,因此必须使用对应的包装类。例如,Integer 替代 intDouble 替代 double 等。

示例:泛型与包装类结合
public class GenericWrapperExample {
    public static void main(String[] args) {
        Box<Integer> integerBox = new Box<>();
        integerBox.setValue(10);  // 装箱操作
        System.out.println("Box contains: " + integerBox.getValue());

        Box<Double> doubleBox = new Box<>();
        doubleBox.setValue(3.14);  // 装箱操作
        System.out.println("Box contains: " + doubleBox.getValue());
    }
}

2.5 泛型的限制

虽然泛型提供了强大的灵活性和类型安全性,但它也有一些限制:

  • 不能使用基本数据类型:如 intchar 等。必须使用包装类 IntegerCharacter 等。
  • 泛型类型擦除:Java 在编译时会进行类型擦除,泛型类型参数会被转换成原始类型。
  • 无法创建泛型数组:因为 Java 无法在运行时确定数组的泛型类型。

3. 包装类与泛型的结合

在 Java 中,使用泛型时通常需要使用包装类来代替基本数据类型。例如,集合类(如 ArrayList)在 Java 中不能直接使用基本数据类型,而是需要使用包装类。

示例:使用包装类的泛型集合

import java.util.*;

public class GenericListExample {
    public static void main(String[] args) {
        // 使用包装类 Integer 而非 int
        List<Integer> intList = new ArrayList<>();
        intList.add(1);
        intList.add(2);
        intList.add(3);

        for (Integer value : intList) {
            System.out.println(value);
        }
    }
}

4. 总结

  • 包装类:用于将基本数据类型转换为对象,Java 提供了每种基本数据类型的对应包装类(如 IntegerDouble 等)。
  • 自动装箱(Auto-boxing)和自动拆箱(Auto-unboxing)让包装类与基本类型之间的转换变得更加简单。
  • 泛型:用于在编译时确定对象的类型,提高类型安全性,避免类型转换的错误。
  • 泛型可以用于类、方法和接口,能够提供更加灵活和通用的代码结构。
  • 泛型与包装类结合使用时,基本数据类型需要通过包装类来表示。