從位元組碼角度分析java泛型陣列的問題
關於java的泛型陣列這個問題,之前就有遇到過,不過當時以為是自己程式碼語法錯誤的問題,現在系統地對java的基礎知識進行深入總結,才發現這個問題某種程度是和泛型的型別擦除機制有關,其實我覺得這個解釋有它的道路但是還是比較勉強。下面我們從位元組碼角度試圖去分析一下java某種意義上是不支援泛型陣列原因
比如原始碼:
List<String>[]list3 = new ArrayList<String>[10];//錯誤定義格式
List<String>[]list3 = new ArrayList[10]; //正確定義格式
List<Long>l = new ArrayList<Long>();
l.add(99l);
Object[] o=list3;
o[0]=l;
list3[0].get(0).length();
位元組碼:
java.util.List<java.lang.String>[]list3;
descriptor: [Ljava/util/List;
flags:
Signature: #16 //[Ljava/util/List<Ljava/lang/Strin
g;>;
61: aload_0
62: bipush 10
64:anewarray #29 // class java/util/ArrayList
67: putfield #31 // Fieldlist3:[Ljava/util/List;
70: new #29 // class java/util/ArrayList
73: dup
74: invokespecial #33 // Methodjava/util/ArrayList."<in
it>":()V
77: astore_1
78: aload_1
79: ldc2_w #34 // long 99l
82: invokestatic #36 // Methodjava/lang/Long.valueOf:(
J)Ljava/lang/Long;
85: invokeinterface #42, 2 // InterfaceMethod java/util/List.
add:(Ljava/lang/Object;)Z
90: pop
91: aload_0
92: getfield #31 // Fieldlist3:[Ljava/util/List;
95: astore_2
96: aload_2
97: iconst_0
98: aload_1
99: aastore
100: aload_0
101: getfield #31 // Fieldlist3:[Ljava/util/List;
104: iconst_0
105: aaload
106: iconst_0
107: invokeinterface #48, 2 // InterfaceMethod java/util/List.
get:(I)Ljava/lang/Object;
112: checkcast #52 // class java/lang/String
115: invokevirtual#54 // Methodjava/lang/String.length:
()I
118: pop
--在程式碼中,我們通過巧妙的步驟用List<Long>物件填充到了List<String>[]陣列中,注意紅色部分,我們執行list3[0].get(0).length();時其實list3[0]的型別已經是List<Long>,所以list3[0].get(0)其實執行時得到的是Long型別物件,但是編譯器是沒這麼聰明的,它還是遵循正常的型別擦除機制對get到的Object物件進行型別轉換checkcast ,這樣就會使我們程式碼執行時會爆出型別轉換的異常。這種情況或許能作為解釋java不支援泛型陣列的一個理由。