• 类型擦除真的能完全擦除一切信息吗?java 泛型揭秘


    背景

    我们都知道泛型本质上是提供类型的"类型参数",它们也被称为参数化类型(parameterized type)或参量多态(parametric polymorphism)。其实泛型思想并不是 Java 最先引入的,C++ 中的模板就是一个运用泛型的例子。

    GJ(Generic Java)是对 Java 语言的一种扩展,是一种带有参数化类型的 Java 语言。用 GJ 编写的程序看起来和普通的 Java 程序基本相同,只不过多了一些参数化的类型同时少了一些类型转换。实际上,这些 GJ 程序也是首先被转化成一般的不带泛型的 Java 程序后再进行处理的,编译器自动完成了从 Generic Java 到普通 Java 的翻译。

    类型擦除真的能完全擦除一切信息吗?java 泛型揭秘

     

    什么是真实的java泛型

    我们都知道编译器会进行泛型擦除,编译器可以在对源程序(带有泛型的 Java 代码)进行编译时使用泛型类型信息保证类型安全,对大量如果没有泛型就不会去验证的类型安全约束进行验证,同时在生成的字节码当中,将这些类型信息清除掉。下面我们先验证一下:

    public static void main(String[] args) {
     ArrayList<Integer> ints = new ArrayList<Integer>();
     ints.add(1); 
     ints.add(2);
     ints.add(3);
     
     ArrayList<String> sts = new ArrayList<String>();
     sts.add("a");
     sts.add("b");
     sts.add("c");
     
     System.out.println(ints.getClass() == sts.getClass()); 
     }
    上面打印的结果是true,原因是:

    按照理解,泛型擦除后将不能找回原来的类型,都是Object形式的,真的如此吗?

    看一下如下代码:

    import java.lang.reflect.ParameterizedType;
    import java.util.ArrayList;
    import java.util.List;
    
    public class ClassTest {
         public static void main(String[] args) throws Exception {
         ParameterizedType type = (ParameterizedType) 
         Bar.class.getGenericSuperclass();
         System.out.println(type.getActualTypeArguments()[0]);
         
         ParameterizedType fieldType = (ParameterizedType) 
         Foo.class.getField("children").getGenericType();
         System.out.println(fieldType.getActualTypeArguments()[0]);
         
         ParameterizedType paramType = (ParameterizedType) 
         Foo.class.getMethod("foo", List.class)
         .getGenericParameterTypes()[0];
         System.out.println(paramType.getActualTypeArguments()[0]);
         
         System.out.println(Foo.class.getTypeParameters()[0]
         .getBounds()[0]);
         }
         
         class Foo<E extends CharSequence> {
         public List<Bar> children = new ArrayList<Bar>();
         public List<StringBuilder> foo(List<String> foo) {return null; }
         public void bar(List<? extends String> param) {}
         }
         
         class Bar extends Foo<String> {}
        }

    打印出

    class java.lang.String
    class com.javapuzzle.davidwang456.ClassTest$Bar
    class java.lang.String
    interface java.lang.CharSequence

    你会发现每一个类型参数都被保留了,而且在运行期可以通过反射机制获取到。那么到底什么是“类型擦除”?至少某些东西被擦除了吧?是的。事实上,除了结构化信息外的所有东西都被擦除了 —— 这里结构化信息是指与类结构相关的信息,而不是与程序执行流程有关的。换言之,与类及其字段和方法的类型参数相关的元数据都会被保留下来,可以通过反射获取到。

    参考资料

    【1】http://techblog.bozho.net/on-java-generics-and-erasure/

    【2】https://www.ibm.com/developerworks/cn/java/j-lo-gj/?mhsrc=ibmsearch_a&mhq=%E7%B1%BB%E5%9E%8B%E6%93%A6%E9%99%A4

  • 相关阅读:
    Struts2的%,#,$的区别,UI标签及其表单radio,checkbox,select回显数据(七)
    Struts2的控制标签库和数据标签库(六)
    Struts2从后端向前端传递数据和OGNL访问用户自定义静态方法(五)
    两个小例子登录和显示全部用户信息的模块(四)
    Struts2的ServletAPI的获取和各种类型的数据获取(三)
    Action的三种实现方式,struts.xml配置的详细解释及其简单执行过程(二)
    Struts2的 两个蝴蝶飞,你好 (一)
    虚拟机安装Centos7系统后优化操作
    Java进程故障排查(CPU资源占用高,接口响应超时,功能接口停滞等)
    zabbix企业微信报警实现
  • 原文地址:https://www.cnblogs.com/davidwang456/p/11880251.html
Copyright © 2020-2023  润新知