<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    首先大家參考一下這篇文章

    http://m.tkk7.com/sean/archive/2005/08/09/9630.html

    sean的這篇文章大部分是對的,但是到最后的結論部分“想想看,我們本來定義的是裝Map<Integer, String>的數組,結果我們卻可以往里面放任何Map,接下來如果有代碼試圖按原有的定義去取值,后果是什么不言自明。”,我覺得可以討論討論。

    其實,sean的文中也提到,Java對泛型的支持其實就是在編譯器中做了做手腳,增加了一些強制類型轉換的代碼,也就是說原來需要我們手動寫的一些強制類型轉換的代碼,在泛型的世界里,Java編譯器就幫我們做了。

    下面來一步步的分析泛型數組的問題:

    Java中的泛型做了什么

    首先看一下Java中的泛型做了什么。看下面這段代碼:
    public class GenTest<T> {
        T value;

        
    public T getValue() {
            
    return value;
        }

        
    public void setValue(T t) {
            value 
    = t;
        }
    }

    使用javap命令反編譯生成的GenTest類的class文件,可以得到下面的輸出:
    javap --p GenTest
    Compiled from 
    "GenTest.java"
    public class GenTest extends java.lang.Object{
    java.lang.Object value;

    public GenTest();
      Code:
       
    0:   aload_0
       
    1:   invokespecial   #12//Method java/lang/Object."<init>":()V
       4:   return

    public java.lang.Object getValue();
      Code:
       
    0:   aload_0
       
    1:   getfield        #23//Field value:Ljava/lang/Object;
       4:   areturn

    public void setValue(java.lang.Object);
      Code:
       
    0:   aload_0
       
    1:   aload_1
       
    2:   putfield        #23//Field value:Ljava/lang/Object;
       5:   return

    }

    我們清楚的看到,泛型T在GenTest類中就是Object類型(java.lang.Object value;)。同樣,get方法和set方法也都是將泛型T當作Object來處理的。如果我們規定泛型是Numeric類或者其子類,那么在這里泛型T就是被當作Numeric類來處理的。

    好,既然GenTest類中沒有什么乾坤,那么我們繼續看使用GenTest的時候又什么新東西:
    public class UseGenTest {

        
    public static void main(String[] args) {
            String value 
    = "value";
            GenTest
    <String> test = new GenTest<String>();
            test.setValue(value);
            String nv 
    = test.getValue();
        }
    }

    使用javap命令反編譯生成的GenTest類的class文件,可以得到下面的輸出:
    D:\mymise\eclipse\workspace\Test\bin>javap --p UseGenTest
    Compiled from 
    "UseGenTest.java"
    public class UseGenTest extends java.lang.Object{
    public UseGenTest();
      Code:
       
    0:   aload_0
       
    1:   invokespecial   #8//Method java/lang/Object."<init>":()V
       4:   return

    public static void main(java.lang.String[]);
      Code:
       
    0:   ldc     #16//String value
       2:   astore_1
       
    3:   new     #18//class GenTest
       6:   dup
       
    7:   invokespecial   #20//Method GenTest."<init>":()V
       10:  astore_2
       
    11:  aload_2
       
    12:  aload_1
       
    13:  invokevirtual   #21//Method GenTest.setValue:(Ljava/lang/Object;)V
       16:  aload_2
       
    17:  invokevirtual   #25//Method GenTest.getValue:()Ljava/lang/Object;
       20:  checkcast       #29//class java/lang/String
       23:  astore_3
       
    24:  return

    }

    重點在17、20和23三處。17就是調用getValue方法。而20則是關鍵——類型檢查。也就是說,在調用getValue方法之后,并沒有直接把返回值賦值給nv,而是先檢查了返回值是否是String類型,換句話說,“String nv = test.getValue();”被編譯器變成了“String nv = (String)test.getValue();”。最后,如果檢查無誤,在23處才會賦值。也就是說,如果沒有完成類型檢查,則會報出類似ClassCastException,而代碼將不會繼續向下執行,這就有效的避免了錯誤的出現。
    也就是說:在類的內部,泛型類型就是被基類型代替的(默認是Object類型),而對外,所有返回值類型為泛型類型的方法,在真正使用返回值之前,都是會經過類型轉換的。

    為什么不支持泛型的數組?

    根據上面的分析可以看出來,泛型其實是挺嚴謹的,說白了就是在“編譯的時候通過增加強制類型轉換的代碼,來避免用戶編寫出可能引發ClassCastException的代碼”。這其實也算是Java引入泛型的一個目的。

    但是,一個頗具諷刺意味的問題出現了:如果允許了泛型數組,那么編譯器添加的強制類型轉換的代碼就會有可能是錯誤的。
    看下面的例子:
    //下面的代碼使用了泛型的數組,是無法通過編譯的
    GenTest<String> genArr[] = new GenTest<String>[2];
    Object[] test 
    = genArr;
    GenTest<StringBuffer> strBuf = new GenTest<StringBuffer>();
    strBuf.setValue(new StringBuffer());
    test[0= strBuf;
    GenTest
    <String> ref = genArr[0]; //上面兩行相當于使用數組移花接木,讓Java編譯器把GenTest<StringBuffer>當作了GenTest<String>
    String value = ref.getValue();// 這里是重點!

    上面的代碼中,最后一行是重點。根據本文第一部分的介紹,“String value = ref.getValue()”會被替換成“String value = (String)ref.getValue()”。當然我們知道,ref實際上是指向一個存儲著StringBuffer對象的GenTest對象。所以,編譯器生成出來的代碼是隱含著錯誤的,在運的時候就會拋出ClassCastException。

    但是,如果沒有“String value = ref.getValue();”這行代碼,那么程序可以說沒有任何錯誤。這全都是Java中多態的功勞。我們來分析一下,對于上面代碼中創建出來的GenTest對象,其實無論value引用實際指向的是什么對象,對于類中的代碼來說都是沒有任何影響的——因為在GenTest類中,這個對象僅僅會被當作是基類型的對象(在這里也就是Object的對象)來使用。所以,無論是String的對象,還是StringBuffer的對象,都不可能引發任何問題。舉例來說,如果調用valued的hashcode方法,那么,如果value指向的是String的對象,實際執行的就是String類中的hashcode方法,如果是StringBuffer的對象,那么實際執行的就是StringBuffer類中的hashcode方法。

    從這里可以看出,即使支持泛型數組也不會帶來什么災難性的后果,最多就是可能引發ClassCastException。而且平心而論,這個還是程序員自己的錯誤,實在算不得是Java編譯器的錯誤。

    但是從另一個角度看,這確實是個巨大的諷刺:泛型是為了消滅ClassCastException而出現的,但是在這個時候它自己卻引發了ClassCastException。咱們中國人把這個叫做搬起石頭砸自己的腳。

    當然制定JSR的那幫子人可能沒學過中文,但是他們肯定是發現了這個令他們糾結的問題。被標榜為Java 5重要feature的泛型竟然陷入了這么一個怪圈。于是,他們在某個月黑風高的晚上,在某個猥瑣的會議室內,悄悄的決定一不做二不休——不支持泛型的數組了。(本段內容系作者猜測,并無任何事實根據,如有雷同,純粹巧合。)

    只有注冊用戶登錄后才能發表評論。


    網站導航:
     
    主站蜘蛛池模板: baoyu116.永久免费视频| 免费A级毛片无码无遮挡内射| 好大好深好猛好爽视频免费| 国产美女无遮挡免费网站| 亚洲国产综合无码一区二区二三区 | 四虎在线视频免费观看| 亚洲videos| 18禁超污无遮挡无码免费网站国产| 亚洲日本国产精华液| 国产免费久久精品99re丫y| 国产成人精品123区免费视频| 久久亚洲精品国产精品婷婷| 无码中文字幕av免费放| 亚洲AV成人一区二区三区在线看 | 亚洲天天在线日亚洲洲精| 中文字幕无线码免费人妻| 亚洲VA中文字幕无码一二三区| 暖暖日本免费中文字幕| 免费一级做a爰片久久毛片潮喷| 国产亚洲综合一区二区三区| 1000部羞羞禁止免费观看视频| 亚洲精品视频免费观看| 精选影视免费在线 | 亚洲日本精品一区二区| 成人浮力影院免费看| 亚洲AV综合色区无码一区爱AV| 久久久免费精品re6| 在线亚洲午夜片AV大片| 免费国产成人午夜私人影视| 9久热这里只有精品免费| 亚洲午夜久久影院| 成人免费视频软件网站| fc2免费人成在线视频| 亚洲AV无码成H人在线观看| 手机看片国产免费永久| 亚洲欧洲精品一区二区三区| 好吊妞在线新免费视频| 成人电影在线免费观看| 中文字幕亚洲精品无码| 亚洲中文字幕无码久久综合网| 亚洲精华国产精华精华液|