• 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的泛型参数化类型已经被擦除掉了。

  • 相关阅读:
    虚方法(virtual)和抽象方法(abstract)的区别
    IT社区
    C#中动态加载和卸载DLL
    应用程序体系结构
    Enterprise Architect 7.0入门教程
    jQuery插件开发基础1
    asp.net页面事件执行顺序
    codesmith4.1破解版
    在Web.config配置文件中自定义配置节点
    小巧实用的节拍器软件FineMetronome介绍 原创
  • 原文地址:https://www.cnblogs.com/twodog/p/12136097.html
Copyright © 2020-2023  润新知