[Java]深入理解泛型

概述

Java泛型是JDK5中引入的一种参数化类型特性
参数化类型
解释:把类型当做参数一样传递
泛型的副作用:<数据类型>只能是引用类型

使用泛型后有以下的好处:

  1. 代码更健壮(只要编译期没有警告,那么运行期就不会出现ClassCastException)
  2. 代码更简洁(不用强转)
  3. 代码更灵活、复用
泛型的使用
public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        list.add("1");
        list.add("2");
        list.add(3);//报错
    }

泛型中的类型在使用时指定,不需要强制类型转换(类型安全,编译器会检查类型)

泛型擦除

先看一段代码:

 public static void main(String[] args) {
        ArrayList<String> strList = new ArrayList<>();
        ArrayList<Integer> intList = new ArrayList<>();
        System.out.println(strList.getClass() == intList.getClass());
    }

打印如下:
在这里插入图片描述
通过打印可以得知,strList和intList类型是一样的,但是如果使用strList = intList进行赋值,会报错,提示类型不匹配,这就是泛型擦除。
通过ASM查看 ArrayList 的add方法如下:
在这里插入图片描述
可以看到我们定义的泛型T都被擦除成了Object,当我们自定义泛型类如下:

public class GenericApi<T extends Comparable<T>> {

    private ArrayList<T> data = new ArrayList<>();

    public void add(T t){
        data.add(t);
    }

    public void reduce(T t){
        if (data.contains(t)){
            data.remove(t);
        }
    }
}

再看生成字节码文件的add方法:
在这里插入图片描述
这里的泛型T被擦除成了Comparable,所以结论如下:在泛型类被类型擦除的时候,之前泛型类中的类型参数部分如果没有指定上限,如 则会被转译成普通的 Object 类型,如果指定了上限如 <T extends Comparable>则类型参数就被替换成类型上限。

泛型与反射

先看一段代码:

public class GenericTest {
    Map<String,String> map;
    public static void main(String[] args) throws Exception {
        Field field = GenericTest.class.getDeclaredField("map");
        System.out.println(field.getGenericType());
        System.out.println(field.getGenericType() instanceof ParameterizedType);
        ParameterizedType type = (ParameterizedType) field.getGenericType();
        System.out.println(type.getRawType());
        for (Type argument: type.getActualTypeArguments()) {
            System.out.println(argument);
        }
        System.out.println(type.getOwnerType());
    }
}

打印如下:
在这里插入图片描述
从上面的打印能看出来,泛型虽然被擦除了,但是还是能通过反射拿出来,因为类的常量池中还是保留泛型信息。

泛型PESC原则

如果你只需要从集合中获取类型T,使用<? extends T> 通配符
如果你只需要将类型T放到集合中,使用<? super T> 通配符
如果你既要获取又要放置元素,则不能使用任何通配符。例如ArrList
PESC即Producer extends Consumer super,为了便于记忆

总结

泛型原理
Java的泛型是JDK5新引入的热性,为了向下兼容,虚拟机其实是不支持泛型,所以Java实现的是一种伪泛型机制,也就是说Java在编译期擦除了所有的泛型信息,这样Java就不需要产生新的类型到字节码,所有的泛型类型最终都是一种原始类型,在Java运行时根本就不存在泛型信息。
擦除泛型过程
1.检查泛型类型,获取目标类型
2.擦除类型变量,并替换为限定类型

  • 如果泛型类型的类型变量没有限定,则用Objcet作为原始类型
  • 如果有限制(T extends XClass),则用Xclass作为原始类型
  • 如果有多个限定(T extends XClass1&XClass2),则使用第一个边界XClass1作为原始类

3.在必要时插入类型转换以保持类型安全
4.生成桥方法以在扩展时保持多态性

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值