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的時候帶了{}執行了賦初值,雖然語法層面沒有什麼區別,可是在編譯以後的結果卻徹底不同。並且執行的結果也徹底不同,
前者執行結果:java

E

後者執行結果:code

class java.lang.String

前者的編譯結果:ip

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>()方法。ci

後者的編譯結果:get

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:it

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的泛型參數化類型已經被擦除掉了。io

相關文章
相關標籤/搜索