【八股】泛型

本文介绍了Java泛型的初衷——代码复用,讨论了类型上下限的限制以及类型擦除的概念。通过实例展示了类型擦除如何影响代码行为,以及编译器如何在类型检查和擦除之间进行平衡。
摘要由CSDN通过智能技术生成

泛型存在的意义?

为了使相同的代码适用于多种数据类型,也就是代码复用。

参数类型上下限限制

  1. <?> 无限制
  2. <? extends E> 声明了类型的上界,表示参数类型可以是他或他的子类。
  3. <? super E> 声明了类型的下界,表示参数类型可以是他或他的父类。

类型擦除

Java泛型这个特性是JDK 1.5才引入的,所以为了兼容之前没有泛型的版本,java的泛型策略是,Java在语法上支持泛型,但在编译阶段会进行类型擦除
类型擦除,就是根据把原类型替换为其原生类型,如果没有限制就替换为Object,如果有上下界限定就替换为原类型的最上界(比如 <T extends number>的类型参数T就被替换为Number,<T super Number>的类型参数T就被替换为Object

拓展:
这个类型擦除也可以引出另一个问题, 为什么要有包装类? 因为基本类型不能作为泛型参数,只有引用类型能作为泛型参数。为什么基本类型不能作为泛型参数? 因为java的泛型策略是,Java在语法上支持泛型,但在编译阶段会进行类型擦除

以下一段代码可以证明Java泛型的类型擦除:

public class Main {
    public static void main(String[] args) throws Exception {

        ArrayList<Integer> list = new ArrayList<Integer>();

        list.add(1);  //这样调用 add 方法只能存储整形,因为泛型类型的实例为 Integer

        list.getClass().getMethod("add", Object.class).invoke(list, "asd");

        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }
    }
}

在这里插入图片描述
定义了一个泛型类型Integer为ArrayList,但当我们利用反射调用ArrayList的add()方法时,却可以存储字符串,说明Integer在编译之后被擦除掉了,只保留了原始类型。原始类型就是擦除了泛型信息后,最后在字节码中的真正类型。

类型擦除的流程

Java编译器是先检查泛型的类型,然后进行类型擦除,最后编译。

public static void main(String[] args) throws Exception {

    ArrayList<String> list = new ArrayList<String>();
    list.add("123");
    list.add(123);//编译错误  java: 不兼容的类型: int无法转换为java.lang.String
}

这段代码编译会报错。说明检查在编译之前,如果检查在编译之后,编译之后变成原始类型Object了,那就不会报错了。
对谁检查?检查是对引用调用的方法进行类型检查,比如上面这段代码就是对list调用的方法里面的参数进行类型检查。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值