什么是泛型,泛型擦除是指什么?

        Java泛型这一重要特性是在JDK 1.5版本中首次引入的。为了确保与早期版本的兼容性,Java泛型的实现采用了一种被形象地称为“伪泛型”的策略。也就是说,尽管Java在语法上支持泛型,但在程序的编译阶段,会进行所谓的“类型擦除”(Type Erasure),即将所有泛型表示替换为具体的类型。

        这样处理后,代码就像完全没有使用泛型一样。 要理解泛型的真正目的,首先需要明白其根本目的是为了实现参数化类型(在不创建新类型的情况下,通过泛型指定的不同类型来约束形参的具体类型)。

        这意味着,在泛型的使用过程中,操作的数据类型被指定为一个参数,这种参数类型可以用在类、接口和方法中,分别被称为泛型类、泛型接口和泛型方法。 泛型的主要优势在于它可以适用于多种数据类型执行相同的代码,从而实现代码复用。在泛型使用过程中,类型在使用时指定,无需进行强制类型转换,因为编译器会负责检查类型,确保类型安全。

泛型上下限

        为了解决泛型中可能出现的类型转换问题,Java泛型引入了类型参数的上下边界机制。这种机制通过使用“extends”关键字来定义上边界和“super”关键字来定义下边界。

        其中,使用“extends A”表示该类型参数可以是A的子类或A本身。在编译时,类型参数会被擦除并替换为具体的类型A,从而确保了类型的安全性。

        这种机制可以有效解决在泛型中使用强制类型转换的问题。编译器可以清楚地知道类型参数的取值范围,只有当传入的实例类型在这个范围内时才允许进行转换。这样,只需要进行一次类型转换即可,运行时会把对象当做A的实例来处理。

        此外,使用上下边界机制还可以提高代码的可读性和可维护性。通过明确指定类型参数的取值范围,可以让代码更加清晰易懂,降低维护成本。

        Java泛型的上下边界机制是一种非常实用的特性,可以有效解决泛型中可能出现的类型转换问题,提高代码的可读性和可维护性,并且使得代码更加灵活和通用。

什么是泛型擦除

探讨什么是泛型擦除之前,大家先来看一个小demo

 public static void main(String[] args) throws Exception {
        List<Integer> integers = new ArrayList<>();
        Class listClass = integers.getClass();
        listClass.getDeclaredMethod("add", Object.class).invoke(integers, "JAVA新视界");
        System.out.println(JSONObject.toJSONString(integers));
    }

程序输出

["JAVA新视界"]

为什么泛型为<Integer>的列表中,可以保存"JAVA新视界"的字符串呢?

如何理解Java中的泛型是伪泛型?泛型中类型擦除

        Java中的泛型并不完全是真正的泛型,因为Java在编译时会对泛型进行类型擦除(Type Erasure)。这意味着在编译后的字节码中,泛型类型信息会被擦除,取而代之的是具体的原生类型(Raw Type)。

        虽然Java泛型在语法上看起来像是泛型,但在编译阶段,泛型参数会被替换为具体的类型。例如,一个泛型列表List<Integer>在编译后的字节码中实际上变成了一个List<Object>,而不是真正的泛型类型。

        这种实现方式是为了保持与早期版本的兼容性,同时提供一些泛型的优点,如类型安全和代码复用。通过类型擦除,Java可以在编译时检查类型,确保类型安全,同时避免运行时出现类型转换异常。

        虽然Java的泛型实现不是真正的泛型,但它仍然提供了很多好处。它可以帮助我们编写更加类型安全和可维护的代码,避免在运行时出现类型转换异常,并且可以提高代码的可重用性。因此,尽管Java中的泛型是“伪泛型”,但在实际编程中仍然非常有用。

泛型的类型擦除原则是:

删除泛型参数的声明,即删除<>及其包围的部分

根据类型参数的上下界推断并替换所有的类型参数为原生态类型。
对于无限制通配符或没有上下界限定的类型参数,将其替换为Object类型。
对于存在上下界限定的类型参数,根据子类替换原则获取父类的限定类型作为替换类型。

为了保证类型安全,必要时插入强制类型转换代码。

自动产生“桥接方法”以保证擦除类型后的代码仍然具有泛型的“多态性”

那么如何进行擦除的呢

  • 擦除类定义中的类型参数 - 无限制类型擦除

当类定义中的类型参数没有任何限制时,在类型擦除中将会直接被替换为Object,如<T>和<?>的类型参数都被替换为超类Object。

  • 擦除类定义中的类型参数 - 有限制类型擦除

当类定义中的类型参数存在限制(上下界)时,在类型擦除中需要替换为类型参数的上界或者下界,比如<T extends Number>和<? extends Number>的类型参数被替换为父类Number,<? super Number>被替换为超类Object。

  • 擦除方法定义中的类型参数

擦除方法定义中的类型参数和擦除类定义中的类型参数是一样的,以擦除方法定义中的有限制类型参数为例:

现在再返回来看刚开始引出的问题,为什么泛型为<Integer>的列表中,可以保存"JAVA新视界"的字符串,因为在运行过程中,会将List<Integer>泛型擦除,变为List<Object>,而注入字符串也是程序在运行阶段执行的,List<Object>支持注入字符串,是不是就解释得通了呢?

  • 8
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JAVA新视界

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值