Java基础——泛型 基础介绍

在Java中,泛型是十分强大的功能,它允许我们在类、方法和接口中使用类型参数,提供安全且灵活的代码。反省通过让你指定通用类型参数来实现“类型独立性”,避免显式的类型转换(数据类型的强转肯定都用过),同时提高了代码的可读性和可维护性。

1.在类上的应用

泛型类指的是在类定义时使用类型参数(比如, , 等)。这种类能够处理多种类型,而不必为每种类型编写多个相似的类。

  • :泛型类型参数,表示任意类型。通常用于类、方法的单一类型参数。
  • :泛型元素类型参数,通常用于表示集合类中元素的类型,如 ListSet 等。
  • :泛型键值对类型参数,常用于表示映射类(如 Map)的键值对类型。

注:这些字母只是符号,代表不同的泛型类型参数,命名可以根据需求进行调整,其他字母也可以使用,其本质上就是一个占位符而已,没有特定的功能,但 Java 的社区约定了这些字母的使用方式,帮助代码更具可读性和一致性,最好还是遵守这些默认的编程规范。

public class Box {
    private T value;

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

    public T get() {
        return value;
    }
}

===========================使用示例======================
Box intBox = new Box<>();
intBox.set(10);  // T 被替换为 Integer 类型
Integer value = intBox.get();  // 返回类型为 Integer
  • 在实例化时,T 被替换为具体的类型(如 IntegerString)。
  • 泛型类提供了类型安全性,在编译时就可以检查类型是否匹配。

2.在方法上的应用

泛型方法是指方法本身使用泛型,允许方法在调用时指定类型。它与泛型类不同,泛型参数只作用于该方法。

public class Util {
    public static  void printArray(T[] array) {  //  表示这是一个泛型方法
        for (T element : array) {
            System.out.print(element + " ");
        }
        System.out.println();
    }
}
  • public static 表示定义一个泛型方法,并且 T 只在该方法的作用域内有效。
  • 方法的参数 T[] array 表明它可以接受任何类型的数组作为参数。

使用

Integer[] intArray = {1, 2, 3};
String[] strArray = {"apple", "banana", "cherry"};

Util.printArray(intArray);  // 输出 1 2 3
Util.printArray(strArray);  // 输出 apple banana cherry
  • 通过 声明泛型参数后,调用该方法时可以传入不同类型的参数。
  • 编译器会自动根据方法传入的参数类型推断泛型类型。

3. 通配符的使用

通配符是 Java 泛型中用于表示未知类型的符号。常见的通配符有三种类型:

  1. ?:表示未知类型。
  2. ? extends T:表示一个类型为 T 或其子类型的类型。
  3. ? super T:表示一个类型为 T 或其父类型的类型。

3.1 ?:表示任何类型

?是最基本的通配符,表示任何类型。通常用于不关系具体类型的情况下。

List list = new ArrayList();  // 可以是任何类型的 List

3.2 ? extends T :表示某一个类型的子类型

? extends T 表示类型为 TT 的子类。这个通配符通常用于读取数据,因为它允许你读取 TT 的子类的元素。

public static void printList(List list) {
    for (Number num : list) {
        System.out.println(num);
    }
}

List intList = new ArrayList<>();
intList.add(1);
intList.add(2);
printList(intList);  // 适用于 List
  • ? extends T 允许传入 TT 的任何子类(包括 IntegerDouble 等)。
  • 通常用于读取数据,因为你可以读取 TT 的任何子类,但不能向集合中添加元素(除了 null)。

3.3 ? super T:表示某一个类型的父类型

? super T 表示类型为 TT 的父类。这个通配符通常用于向集合中添加数据,因为它允许你添加 TT 的子类的元素。

public static void addNumbers(List list) {
    list.add(10);  // 可以安全地添加 Integer 或其子类
}

List numberList = new ArrayList<>();
addNumbers(numberList);  // 可以传入 List 或 List
 
  
  • ? super T 允许传入 TT 的任何父类(包括 Object)。
  • 通常用于向集合中添加数据,因为它保证你可以添加 T 类型或其子类的对象。
通配符的总结
通配符 含义 用法
? 表示任何类型 用于不关心类型时(例如:List
? extends T 表示 TT 的子类 用于读取数据(例如:List
? super T 表示 TT 的父类 用于向集合中添加数据(例如:List
  • ? 用于无法确定具体类型时,例如在某些方法中只需要通用类型参数时。
  • ? extends T 用于方法参数中,当你只需要读取集合中的元素,且知道它们是 TT 的子类时。
  • ? super T 用于方法参数中,当你需要向集合中添加元素,且知道它们是 TT 的父类时。

 4. 泛型的限制

尽管泛型在 Java 中非常强大,但它也有一些限制:

  • 不能使用基本数据类型:Java 的泛型只能使用对象类型,不能直接使用基本数据类型,如 intchar 等。你可以使用包装类,如 IntegerCharacter 等。

  • 不能创建泛型数组:由于泛型类型在运行时会被擦除,所以你不能创建泛型数组。

// 错误,不能创建泛型数组
// T[] array = new T[10];

// 正确,使用 Object 数组
Object[] array = new Object[10];
  • 类型擦除:Java 泛型使用类型擦除(Type Erasure)机制,在运行时泛型类型信息被擦除,只保留原始类型。因此,你不能通过反射获取泛型的实际类型。

public class Box {
    // 在运行时 T 会被擦除成 Object
}

注:Java 泛型中,?(通配符)和字母(如 TEKV 等)的泛型类型参数的确都能够表示某种类型,但它们的使用场景和目的有很大的区别。简而言之,字母泛型通常是在定义类、方法或者接口时用于表示某个类型,而通配符 ?则是在使用这些类、方法时表示任意类型,并且具有更强的灵活性。

5. 总结

  • 字母泛型:用于定义类或方法时,表示一个占位符类型。类型在使用时确定,编译器会进行类型检查。
  • 通配符 ?:用于方法参数中,表示一个未知类型。在方法内部,? 提供了更灵活的类型接受能力,同时通过 ? extends T? super T 可以限定操作范围(如只允许读取、只允许写入)。
  • 通配符增加了代码的灵活性,尤其在处理泛型集合时,避免了类型的严格限制,使得方法能够接受多种类型的数据。

你可能感兴趣的:(java,开发语言)