Java 基础 -- 泛型核心知识点详解

发布于:2024-05-23 ⋅ 阅读:(105) ⋅ 点赞:(0)

在Java编程中,泛型(Generics)是一个强大的特性,它允许程序员在编写类、接口和方法时定义类型参数(type parameters)。这些类型参数在类、接口或方法被实例化时(例如,创建对象或使用方法时)被具体的类型所替换。通过泛型,我们可以创建可重用的组件,这些组件可以处理多种数据类型,同时保证了类型安全并减少了类型转换的错误。

一、核心知识点

1. 泛型类

泛型类就是具有一个或多个类型参数的类。类型参数被尖括号(< >)括起来,并放在类名的后面。例如:

public class Box<T> {  
    private T t;  
  
    public void set(T t) { this.t = t; }  
    public T get() { return t; }  
}

在上面的代码中,T 是一个类型参数,它可以在创建 Box 对象时指定为任何类型。

2. 泛型接口

与泛型类类似,泛型接口也包含类型参数。例如:

public interface List<E> {  
    void add(E e);  
    E get(int index);  
    // ... 其他方法 ...  
}

在这个例子中,List 是一个泛型接口,它有一个类型参数 E。

3. 泛型方法

泛型方法是指可以应用于多种数据类型的方法。类型参数放在方法签名的返回类型之前在修饰符和返回类型之间)。例如:

public static <T> void printArray(T[] array) {  
    for (T item : array) {  
        System.out.print(item + " ");  
    }  
    System.out.println();  
}

在这个例子中,printArray 是一个泛型方法,它可以接受任何类型的数组作为参数。

4. 类型通配符

类型通配符(?)表示未知的类型。它主要有两种形式:上界通配符(? extends Type)和下界通配符(? super Type)。例如:

List<? extends Number> numbers; // 可以存放Number及其子类对象  
List<? super Integer> integers; // 可以存放Integer及其父类对象

5. 泛型擦除

由于Java的泛型是编译时类型检查机制,所以在运行时所有的泛型信息都会被擦除(Type Erasure)。这意味着在运行时,Java虚拟机(JVM)并不知道泛型参数的具体类型

应用实例
示例1:泛型类

public class Main {  
    public static void main(String[] args) {  
        Box<Integer> integerBox = new Box<>();  
        integerBox.set(10);  
        System.out.println(integerBox.get()); // 输出: 10  
  
        Box<String> stringBox = new Box<>();  
        stringBox.set("Hello");  
        System.out.println(stringBox.get()); // 输出: Hello  
    }  
}

示例2:泛型接口
假设我们有一个简单的泛型接口实现:

public class ArrayList<E> implements List<E> {  
    // 实现List接口的方法...  
}  
  
// 使用ArrayList  
List<String> stringList = new ArrayList<>();  
stringList.add("Apple");  
stringList.add("Banana");  
System.out.println(stringList.get(0)); // 输出: Apple

示例3:泛型方法

public class Main {  
    public static void main(String[] args) {  
        Integer[] intArray = {1, 2, 3, 4, 5};  
        printArray(intArray); // 输出整数数组  
  
        String[] stringArray = {"Hello", "World"};  
        printArray(stringArray); // 输出字符串数组  
    }  
}

6. 泛型与原始类型

在Java中,如果泛型类没有指定类型参数,那么它会被视为原始类型(Raw Type)。使用原始类型通常是不安全的,因为它会绕过泛型提供的类型检查。然而,在Java 5之前编写的代码中,可能仍然存在原始类型的使用。为了兼容旧代码,Java允许将泛型与原始类型混合使用,但应尽量避免。

7. 泛型与静态上下文中的类型推断

Java 7引入了菱形操作符(diamond operator,<>),允许在实例化泛型类时省略类型参数,编译器会自动推断出类型参数。这在静态上下文中特别有用,例如创建集合时:

List<String> list = new ArrayList<>(); // 使用菱形操作符进行类型推断

8. 泛型与数组

在Java中,创建泛型数组是不允许的,因为泛型类型在运行时会被擦除,这可能导致类型不安全问题。但是,你可以创建数组的泛型引用,但这通常是不推荐的,因为这会绕过泛型提供的类型安全保证。

9. 泛型与反射

由于泛型类型在运行时会被擦除,因此使用反射来操作泛型类型时需要特别小心。反射API通常与原始类型一起使用,而不是泛型类型。如果需要通过反射来操作泛型类型,可能需要借助一些额外的机制(如类型令牌,Type Token)来保留泛型类型信息。

10. 泛型与泛型边界

泛型边界允许我们限制泛型参数的类型。例如,我们可以创建一个泛型类,其类型参数必须是某个特定类的子类或实现了某个特定接口。这在设计API时特别有用,因为它允许我们限制可以传递给泛型参数的类型。


网站公告

今日签到

点亮在社区的每一天
去签到