1. 程式人生 > >從位元組碼角度分析java泛型陣列的問題

從位元組碼角度分析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不支援泛型陣列的一個理由。