• Java泛型和编译优化的一个例子


    public class Main {
        public static void main(String[] args) {
            ArrayList<String> strList = new ArrayList<String>();
            Type type = ((ParameterizedType)strList.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
            System.out.println(type);
        }
    }
    
    public class Main {
        public static void main(String[] args) {
            ArrayList<String> strList = new ArrayList<String>(){};
            Type type = ((ParameterizedType)strList.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
            System.out.println(type);
        }
    }

    这两个例子唯一的区别是后者的new ArrayList<String>(){}初始化strList的时候带了{}执行了赋初值,虽然语法层面没有什么区别,但是在编译之后的结果却完全不一样。而且执行的结果也完全不一样,
    前者执行结果:

    E

    后者执行结果:

    class java.lang.String

    前者的编译结果:

    public static void main(java.lang.String[]);
        descriptor: ([Ljava/lang/String;)V
        flags: ACC_PUBLIC, ACC_STATIC
        Code:
          stack=2, locals=3, args_size=1
             0: new           #2                  // class java/util/ArrayList
             3: dup
             4: invokespecial #3                  // Method java/util/ArrayList."<init>":()V
             7: astore_1
             8: aload_1
             9: invokevirtual #4                  // Method java/lang/Object.getClass:()Ljava/lang/Class;
            12: invokevirtual #5                  // Method java/lang/Class.getGenericSuperclass:()Ljava/lang/reflect/Type;
            15: checkcast     #6                  // class java/lang/reflect/ParameterizedType
            18: invokeinterface #7,  1            // InterfaceMethod java/lang/reflect/ParameterizedType.getActualTypeArguments:()[Ljava/lang/reflect/Type;
            23: iconst_0
            24: aaload
            25: astore_2
            26: getstatic     #8                  // Field java/lang/System.out:Ljava/io/PrintStream;
            29: aload_2
            30: invokevirtual #9                  // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
            33: return

    这个逻辑很简单,就是简单的invokespecialArrayList<init>()方法。

    后者的编译结果:

    public static void main(java.lang.String[]);
        descriptor: ([Ljava/lang/String;)V
        flags: ACC_PUBLIC, ACC_STATIC
        Code:
          stack=2, locals=3, args_size=1
             0: new           #2                  // class Main$1
             3: dup
             4: invokespecial #3                  // Method Main$1."<init>":()V
             7: astore_1
             8: aload_1
             9: invokevirtual #4                  // Method java/lang/Object.getClass:()Ljava/lang/Class;
            12: invokevirtual #5                  // Method java/lang/Class.getGenericSuperclass:()Ljava/lang/reflect/Type;
            15: checkcast     #6                  // class java/lang/reflect/ParameterizedType
            18: invokeinterface #7,  1            // InterfaceMethod java/lang/reflect/ParameterizedType.getActualTypeArguments:()[Ljava/lang/reflect/Type;
            23: iconst_0
            24: aaload
            25: astore_2
            26: getstatic     #8                  // Field java/lang/System.out:Ljava/io/PrintStream;
            29: aload_2
            30: invokevirtual #9                  // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
            33: return

    这里就奇怪了,加了{}之后竟然生成了内部类Main$1:

    final class Main$1 extends java.util.ArrayList<java.lang.String>
    ...
    {
      Main$1();
        descriptor: ()V
        flags:
        Code:
          stack=1, locals=1, args_size=1
             0: aload_0
             1: invokespecial #1                  // Method java/util/ArrayList."<init>":()V
             4: return
          LineNumberTable:
            line 8: 0
    }
    Signature: #9                           // Ljava/util/ArrayList<Ljava/lang/String;>;
    ...

    java.util.ArrayList<java.lang.String>的子类,这也就解释了后者的执行结果为何可以解析到strList的泛型参数化类型是java.lang.String了,因为它的实际类型在JVM执行的时候清楚地被标记成了内部类Main$1这个java.util.ArrayList<java.lang.String>的子类。而前者的strList的泛型参数化类型已经被擦除掉了。

  • 相关阅读:
    标准化:释放物联网全部潜力的万能钥匙
    Linux系统中如何删除交换文件,来解决突然关闭命令行,导致文件无法打开的问题
    echarts设置图例以及网络格局的相关细节设置
    JSON.parse()与JSON.stringify()的区别,具体例子,一看就明白
    HttpServletRequest
    HttpServletResponse
    JavaWeb核心之Servlet
    Http协议和Tomcat服务器
    dom4j解析
    DTD和Schema约束
  • 原文地址:https://www.cnblogs.com/twodog/p/12136095.html
Copyright © 2020-2023  润新知