博客已轉到HuJinPu 's blog

          http://blog.csdn.net/hujinpu

          首頁 新隨筆 聯系 聚合 管理
            24 Posts :: 0 Stories :: 25 Comments :: 0 Trackbacks

          大家先看看下面這段小程序

          import ?java.util.ArrayList;
          import ?java.util.List;

          // 申明一個泛型類
          public ? class ?GenericClass? {
          ????
          ????
          public ? static ? void ?main(String?[]?args)? {
          ????????List
          < Integer > ?list? = ? new ?ArrayList < Integer > ();
          ????????list.add(
          1 );
          ????????list.add(
          2 );
          ????????
          new ?Product().prt(list);
          ????}

          }


          // 制造一個類用于說明問題
          class ?Product ? {
          ????
          public ? void ?prt(List < String > ?lt)? {
          ????????System.out.println(lt);
          ????}

          }


          ?

          編譯器報錯,說無法將Product中的prt(java.util.List<java.lang.String>)應用于(java.util.List<java.lang.Integer>)。前面定義了List<Integer> list = new ArrayList<Integer>();后面卻調用 public void prt(List<String> lt)用list做參數,肯定是錯誤的用法。編譯器報錯的行為是很正確的,他幫助你避免了潛在錯誤的發生。這里要注意泛型的作用:List<Integer>和List<String>雖然看著都是List,但編譯器把他們當作不同的class,不能相互替代。這是泛型的基本原則。你可以把他們看成一個是Class1, 一個是Class2, 當然不能給一個需要類型為Class1的參數的方法傳一個類型為Class2的參數的方法啦。

          再來看上面程序稍微改動一處的情況

          import ?java.util.ArrayList;
          import ?java.util.List;

          // 申明一個泛型類
          public ? class ?GenericClass? {
          ????
          ????
          public ? static ? void ?main(String?[]?args)? {
          ????????List
          < Integer > ?list? = ? new ?ArrayList < Integer > ();
          ????????list.add(
          1 );
          ????????list.add(
          2 );
          ????????
          new ?Product().prt(list);
          ????}

          }


          // 制造一個類用于說明問題
          class ?Product < T > ? {
          ????
          public ? void ?prt(List < String > ?lt)? {
          ????????System.out.println(lt);
          ????}

          }


          編譯器說使用了未經檢查或不安全的操作,但能編譯通過并運行顯示 [1, 2]。

          這又是為什么呢?就是紅色的那一個<T>就變化這么大嗎?似乎不是和剛才效果應該一樣拉,怎么這回又可以了?

          原因是這樣的:第次程序里面,只是把class Product改成了class Product<T>,盡管類型T在Product的代碼里壓根從沒用到,但是這個定義把一個普通類(class)變成了原始類型(raw class)。generic class Product<T>在JVM運行時是不存在的,Product這個原始類型不是類型安全的。因為在new Product.prt(list)里面,使用的是原始類型的Product,所以里面的list也會被擦拭成原始類型的,所以類型就符合了,不會有編譯錯誤而可以運行。

          雖然這個時候程序盡管可以運行,但其使用泛型的方法,無疑是錯誤的。 在這里我只是想和大家分析一些泛型的細節問題。要大家通過這個細節明白泛型的細節之處(檫試,原始類型)。具體的內容我就不在說了,很多書都有。推薦java參考大全5edition page264 和 core Java I 7edition Chapter 13. Generic Programming??

          posted on 2006-08-28 16:19 livahu 閱讀(1662) 評論(5)  編輯  收藏 所屬分類: Java

          Feedback

          # re: 關于jdk1.5泛型的思考 2006-08-28 17:17 海藍
          @livahu
          你在原因部分說的內容我看不懂啊,感覺你說的原因和結果之間似乎沒什么必然的聯系,可以再整理一下嗎?  回復  更多評論
            

          # re: 關于jdk1.5泛型的思考 2006-08-28 18:29 路人甲
          這個問題我想的確是作者沒有說清楚。不過只要親自用編譯器試一下應該就可以很容易理解了。這里斗膽幫作者稍微深入地解釋一下,如果說錯了還請不吝賜教,但愿不會誤人子弟。

          首先,第一段程序里面,前面定義了List<Integer> list = new ArrayList<Integer>();
          后面卻調用void prt(List<String> l)用list做參數,肯定是錯誤的用法。編譯器報錯的行為是很正確的,他幫助你避免了潛在錯誤的發生。

          這里要注意泛型的作用。List<Integer>和List<String>雖然看著都是List,但編譯器把他們當作不同的class,不能相互替代。這是泛型的基本原則。你可以把他們看成一個是Class1, 一個是Class2, 當然不能給一個需要類型為Class1的參數的方法傳一個類型為Class2的參數的方法啦。

          而第二段程序里面,只是把class Product改成了class Product <T>,盡管類型T在Product的代碼里壓根從沒用到,只是這個定義把一個普通類(class)變成了原始類型(raw class)。其實可以自己試一下,一旦把Fangxin.main()里面的new Product().prt(list) 改成了new Product<Integer>().prt(list), (這里面的Integer可以換成任何一個合法的類),那么warning沒有了,原來的error又回來了。

          也就是說,一旦把Product定義成了原始類型,那么在使用這個class的時候也就應該使用Product<T>的形式,否則的話,編譯器會認為你的行為不正?;蚴呛芪kU,所以給你一個warning(也許你只是忘了寫呢)。正像作者原文里寫道的:

          generic class Product<T>在JVM運行時是不存在的,Product叫原始類型,原始類型不是類型安全的.這個在編譯時是檢測不出的,運行時才報錯.
          (這里其實不會報錯,只是因為可能會報錯,所以編譯器給你一個warning)。

          而當一個generic class使用原始類型時,其方法里的參數也就相應的使用了原始形態,如此列的java.util.List而不是java.util.List<String>
          固new Product().prt(lt)時可以運行.

          (這句是說,因為在new Product.prt(list)里面,你使用的是原始類型的Product,所以里面的list也是原始類型的,所以類型就符合了,不會有編譯錯誤而可以運行)。

          但是這個時候盡管可以運行,但程序的邏輯,至少其使用泛型的方法,無疑是錯誤的。

          個人認為這個程序應該改成這樣才是正確地使用泛型編程的方式:

          import java.util.ArrayList;
          import java.util.List;

          public class Fangxin {

          public static void main(String [] args) {
          List<Integer> list = new ArrayList<Integer>();
          list.add(1);
          list.add(2);
          new Product<Integer>().prt(list);
          }

          }

          class Product<T> {
          public void prt(List<T> l) {
          System.out.println(l);
          }
          }

          最后加一句,編譯器給出error和warning不是故意跟你作對,給你添麻煩,而是為你寫出正確的程序提出最好的幫助。所以應該盡量讓程序沒有任何編譯錯誤(這個自然)和警告才是正途。  回復  更多評論
            

          # re: 關于jdk1.5泛型的思考 2006-08-28 20:52 livahu
          很感謝路人甲的指正,我確實沒有表達清楚我的想法,我想通過路人甲的指正,大家應該明白了泛型的細節之處,這里的帶有明顯錯誤和警告的程序不是要大家去模仿,而是要大家通過這個細節明白泛型的細節之處(檫試,原始類型).具體的內容我就不在說了,很多書都有,推薦java參考大全5edition page264 和 core Java I 7edition Chapter 13. Generic Programming  回復  更多評論
            

          # re: 關于jdk1.5泛型的思考 2006-08-29 09:00 Dedian
          good article, just for supplement:

          http://www.aygfsteel.com/dedian/archive/2006/06/23/54615.html  回復  更多評論
            

          # re: 關于jdk1.5泛型的思考 2006-09-01 10:16 Spike Wang
          這樣的用法1.5以后才有,最好不要亂用泛型。

          我建議如果是新項目使用無所謂。

          如果是和以前系統協作那么最好避免。

          免得給自己找麻煩。

          在泛型還么大量使用的時候,盡量避免使用。

            回復  更多評論
            

          主站蜘蛛池模板: 湘阴县| 安阳市| 西宁市| 溧阳市| 宿迁市| 海林市| 内乡县| 巴林左旗| 葵青区| 静乐县| 娄烦县| 安平县| 龙胜| 玉田县| 扬中市| 辽阳县| 泽州县| 龙泉市| 涟水县| 江西省| 兴业县| 永康市| 巫山县| 兴国县| 扬中市| 汝州市| 霍邱县| 镇安县| 柳江县| 巴林左旗| 英德市| 尖扎县| 汪清县| 遂溪县| 麦盖提县| 孟津县| 弥勒县| 通渭县| 巨鹿县| 丰宁| 清苑县|