Java 中的泛型允许在类、接口和方法中定义类型参数(Type Parameters),从而提供编译时类型安全和减少强制类型转换的需要。

泛型是如何工作的?

当你定义一个泛型类或方法时,可以使用一个或多个类型参数代替具体的类型。例如:
public class Box<T> {    private T t; // T stands for "Type"    public void set(T t) { this.t = t; }    public T get() { return t; }}public <U> void inspect(U u){System.out.println("U:"+u.getClass().getName());}

在上面的例子中,Box 类使用了一个类型参数 T,这意味着它可以用来存储任何类型的对象,并且使用该对象时不需要进行类型转换。

泛型的工作原理是,在编译时期进行类型检查,确保代码中使用的类型是正确的。然后,在运行时期,泛型信息会被擦除,这就引入了类型擦除的概念。

类型擦除(Type Erasure)

类型擦除是 Java 泛型的一个特点,指的是编译器在编译泛型代码时会将所有的类型参数替换为它们的限定类型(bounded type),若未指定限定类型则使用 Object,然后在相关地方插入类型转换以保持类型安全。这使得泛化的类型能够与 Java 早期版本的代码兼容。

例如,以下泛型 Box 类:

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

在编译之后会变成:

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

这种方式意味着运行时类型信息关于泛型参数是不存在的(称为类型擦除)。因此,在运行时无法得知一个集合的元素类型是什么。

举个栗子

假设我们有以下的泛型接口和类:

interface List<E> {    void add(E e);    Iterator<E> iterator();}class StringList implements List<String> {    // 实现接口的方法}
在运行时,StringList 的实例只知道它实现了一个处理 Object 类型的 List 接口,对 String 类型的泛型参数没有信息。在编译期,这些信息是已知的,并且可以防止将非 String 类型加入到 StringList 中,但在运行时,所有的泛型类型检查都会消失,StringList 就像是处理 Object 的普通 List。

为了维护类型安全,编译器在需要的时候添加强制类型转换。比如 get()方法的调用者将会得到一个编译器插入的对返回值的强制类型转换。这样即使类型信息已经被擦除,代码在运行时也能正常工作,而且不会出现类型错误。

本篇文章来源于微信公众号: 互联网面试小帮手



微信扫描下方的二维码阅读本文

此作者没有提供个人介绍
最后更新于 2024-05-24