• java 泛型实现原理


    泛型思想最早在C++语言的模板(Templates)中产生,Java后来也借用了这种思想。虽然思想一致,但是他们存在着本质性的不同。

    C++中的模板是真正意义上的泛型,在编译时就将不同模板类型参数编译成对应不同的目标代码,List<Integer>和List<String>是两种不同的类型,这种泛型被称为真正泛型。

    这种泛型实现方式,会导致类型膨胀,因为要为不同具体参数生成不同的类。

    Java中List<Integer>和List<String>虽然在源代码中属于不同的类,但是编译后的字节码中,他们都被替换成原始类型,而两者的原始类型的一样的(List<Object>),所以在运行时,List<Integer>与List<String>就是同一个类。

    Java中的泛型是一种特殊的语法,通过类型擦除实现,这种泛型称为伪泛型。

    类型擦除,是指将泛型类型实例关联到同一份字节码上。编译器只为泛型类型生成一份字节码,并将其实例关联到这份字节码上。

    类型擦除的关键在于从泛型类型中清除类型参数的相关信息,并且再必要的时候添加类型检查和类型转换的方法。

            List<Integer> intList = new ArrayList<>();
            intList.add(3);
            List<String> strList  = new ArrayList<>();
            strList.add("Hello");
    
            System.out.println(intList.getClass() == strList.getClass());  // 输出结果为true

    intList与strList都属于同一个类。

    创建一个只能存储Integer的ArrayList对象,在add一个整型数值后,利用反射调用add(Object o)add一个asd字符串,此时运行代码不会报错,运行结果会打印出1和asd两个值。这时再里利用反射调用add(Integer o)方法,运行会抛出codeNoSuchMethodException异常。这充分证明了在编译后,擦除了Integer这个泛型信息,只保留了原始类型。

    创建一个List<Integer>对象intList,利用反射调用其add()方法,向intList中添加一个String类元素,运行代码不会报错。

            List<Integer> intList = new ArrayList<>();
            intList.add(3);
    
            intList.getClass().getMethod("add", Object.class).invoke(intList, "Hello");
            for (int i = 0; i < intList.size(); i++) {
                System.out.println(intList.get(i)); 
            }
    
            // 输出结果为
            // 3
            // Hello

    这说明在编译后,擦出了Integer这个泛型信息,intList为原始类型List<Object>。

    修改代码getMethod("add", Object.class),改为getMethod("add", Integer.class)

    //      NoSuchMethodException: 
            intList.getClass().getMethod("add", Integer.class).invoke(intList, "Hello");

    运行报错,intList的类List<Integer>中没有("add", Integer.class)方法,只有("add", Object.class)。

    自动类型转换

    Java的泛型除了类型擦除之外,还会自动生成checkcast指令进行强制类型转换。

            List<Integer> intList = new ArrayList<>();
            intList.add(3);
    
            int a = intList.get(0);

    使用intList的get方法返回的是Integer类型的对象。

  • 相关阅读:
    如何退出天擎
    git彻底删除或变更子模块
    湖北校园网PC端拨号算法逆向
    PPPoE中间人拦截以及校园网突破漫谈
    vscode打开django项目pylint提示has not "object" member
    从客户端取到浏览器返回的oauth凭证
    教程视频如何压制体积更小
    windows中的软链接硬链接等
    关于博客园和独立博客的一些打算
    拉勾抓职位简单小爬虫
  • 原文地址:https://www.cnblogs.com/deltadeblog/p/9222167.html
Copyright © 2020-2023  润新知