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

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

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

    Picses' sky

    Picses' sky
    posts - 43, comments - 29, trackbacks - 0, articles - 24

    [譯者按:]

    Bruce Eckel在前不久寫了一片批判Java的泛型的文章,結(jié)合他在OO上浸淫多年的功力,一眼就看出了Java的泛型和其他例如C++,Python,Ruby等等這些語言的泛型的差別。

    不過平心而論,Bruce Eckel的批評是比較中肯的,因?yàn)樗部吹搅薐ava和其他這些面向?qū)ο蟮恼Z言之間的差別,他也可以理解Java實(shí)現(xiàn)出了這樣的泛型。

    另外,如果大家不知道Ruby是什么,可以參考下面的網(wǎng)站:http://www.ruby-lang.org/en/

    [補(bǔ)充]添加一段Bruce Eckel自己的評論:

    Guess what. I really don't care. You want to call it "generics," fine, implement something that looks like C++ or Ada, that actually produces a latent typing mechanism like they do. But don't implement something whose sole purpose is to solve the casting problem in containers, and then insist that on calling it "Generics." Of course, Java has long precedence in arrogantly mangling well- accepted meanings for things: one that particularly stuck in my craw was the use of "design pattern" to describe getters and setters. In JDK 1.4 we were told some lame way to use assertions which was a backward justification for them being disabled by default. JDK 1.4 also had to invent its own inferior logging system rather than using the openly created, well-tested and well-liked Log4J. And we've also been told many times about how Java has been as fast or faster than C++, or about how one or another feature is great and flawless. I point to the threads implementation which has had major changes quietly made from version to version with not so much as a peep of apology or admission that "hey, we really screwed up here." Or maybe I was just not on that particular announcement list.

    昨晚,我作為嘉賓被Silicon Valley的模式組邀請去參加他們的一個(gè)研討會,并且讓我來決定討論的主題,為了更好的了解JDK1.5,我選擇了Java的Generics(泛型),最后討論的結(jié)果是我們大家都有點(diǎn)震驚。我們討論的主要素材是最新的Sun推出的Java 泛型手冊。我對“參數(shù)化類型”的經(jīng)驗(yàn)來自于C++,而C++的泛型又是基于ADA的Generics,事實(shí)上,Lisp語言是第一個(gè)實(shí)現(xiàn)了泛型的語言,有人說Simula語言也很早就有泛型了。在這些語言中,當(dāng)你使用參數(shù)化的類型的時(shí)候,這個(gè)參數(shù)是作為一種隱式類型(latent type)的:一種被實(shí)現(xiàn)出了如何使用,但是卻沒有顯式的聲明的類型。也就是說,隱式類型是一種通過你調(diào)用方法來實(shí)現(xiàn)的。例如,你的模板方法是某個(gè)類型中的f()和g(),那么接下來你實(shí)現(xiàn)了一個(gè)類型包含了f()和g()這兩個(gè)方法,而事實(shí)上這個(gè)類型可能從來被定義過。舉個(gè)例子,在Python中,你可以這樣做:

    def speak(anything):
        anything.talk()
    
    注意到,這里對anything沒有任何的類型限制,只是一個(gè)標(biāo)識而已,假設(shè)這個(gè)類型能做一個(gè)叫做speak()的操作,就象實(shí)現(xiàn)了一個(gè)Interface一樣,但是事實(shí)上你根本不需要去真的實(shí)現(xiàn)這樣一個(gè)Interface,所以叫做隱式。現(xiàn)在我可以實(shí)現(xiàn)這樣一個(gè)“狗狗和機(jī)器人”的例子:
    class Dog:
        def talk(self):  print "Arf!"
        def reproduce(self): pass
    
    class Robot:
        def talk(self): print "Click!"
        def oilChange(self): pass
    
    a = Dog()
    b = Robot()
    speak(a)
    speak(b)
    
    Speak()方法不關(guān)心是否有參數(shù)傳入,所以我可以傳給它任何的東西,就象我傳入的對象中支持的talk()方法一樣。我相信在Ruby語言中的實(shí)現(xiàn)是和Python一致的。在C++中你可以做相同的事情:
    class Dog {
    public:
      void talk() { }
      void reproduce() { }
    };
    
    class Robot {
    public:
      void talk() { }
      void oilChange() { }
    };
    
    template void speak(T speaker) {
      speaker.talk();
    }
    
    int main() {
      Dog d;
      Robot r;
      speak(d);
      speak(r);
    }
    
    再次聲明,speak()方法不關(guān)心他的參數(shù)類型,但是在編譯的時(shí)候,他仍然能保證他能傳出那些信息。但是在Java(同樣在C#)語言中,你卻不能這樣做,下面這樣的做法,在JDK1.5中就編譯不過去(注意,你必須添加source – 1.5來使得javac能識別你的泛型代碼)
    public class Communicate  {
      public  void speak(T speaker) {
        speaker.talk();
      }
    }
    
    但是這樣卻可以:
    public class Communicate  {
      public  void speak(T speaker) {
        speaker.toString(); // Object methods work!
      }
    }
    
    Java的泛型使用了“消磁”,也就是說如果你打算表示“任何類型”,那么Java會把這個(gè)任何類型轉(zhuǎn)化為Object。所以當(dāng)我說不能象C++/ADA/Python一樣真正的代表“任何類型”,他只是代表Object。看來如果想讓Java也能完成類似的工作必須定義一個(gè)包含了speak方法的接口(Interface),并且限制只能傳入這個(gè)接口。所以下面這樣的代碼能編譯:
    interface Speaks { void speak(); }
    
    public class Communicate  {
      public  void speak(T speaker) {
        speaker.speak();
      }
    }
    
    而這樣是說:T必須是一個(gè)實(shí)現(xiàn)了speak接口的類或者這樣的一個(gè)子類。所以我的反映就是,如果我不得不聲明這樣的一個(gè)子類,我為什么不直接用繼承的機(jī)制那?干嗎還非要弄的這么費(fèi)事還糊弄人呢?就象這樣:
    interface Speaks { void speak(); }
    
    public class CommunicateSimply  {
      public void speak(Speaks speaker) {
        speaker.speak();
      }
    }
    
    在這個(gè)例子里,泛型沒有任何的優(yōu)勢,事實(shí)上,如果你真的這樣使用,會讓人迷糊的,因?yàn)槟銜煌5纳︻^:為什么這里他需要一個(gè)泛型那?有什么優(yōu)勢?回答是:什么都沒有。完全沒有必要用泛型,泛型完全沒有優(yōu)勢。如果我們要用泛型來實(shí)現(xiàn)上面的“狗狗和機(jī)器人”的例子,我們被迫要使用接口或者父類,用這樣顯式的方式來實(shí)現(xiàn)一個(gè)所謂的“泛型”。
    interface Speaks { void talk(); }
    
    class Dog implements Speaks {
      public void talk() { }
      public void reproduce() { }
    }
    
    class Robot implements Speaks {
      public void talk() { }
      public void oilChange() { }
    }
    
    class Communicate {
      public static  void speak(T speaker) {
        speaker.talk();
      }
    }
    
    public class DogsAndRobots {
      public static void main(String[] args) {
        Dog d = new Dog();
        Robot r = new Robot();
        Communicate.speak(d);
        Communicate.speak(r);
      }
    }
    
    (注意到在泛型中你用的extends而不是implements,implements是不能使用的,Java是精確的,并且Sun說了必須這樣做)再一次,泛型和簡單的接口實(shí)現(xiàn)相比沒有任何的優(yōu)勢。
    interface Speaks { void talk(); }
    
    class Dog implements Speaks {
      public void talk() { }
      public void reproduce() { }
    }
    
    class Robot implements Speaks {
      public void talk() { }
      public void oilChange() { }
    }
    
    class Communicate {
      public static void speak(Speaks speaker) {
        speaker.talk();
      }
    }
    
    public class SimpleDogsAndRobots {
      public static void main(String[] args) {
        Dog d = new Dog();
        Robot r = new Robot();
        Communicate.speak(d);
        Communicate.speak(r);
      }
    }
    
    如果我們真的寫一段能真正代表“任何類型”的泛型代碼的話,那么這段代碼所代表的類型只能是Object,所以我們的泛型代碼只能說是Object的一個(gè)方法而已。所以,事實(shí)上,我們只能說Java的泛型只是對Object類型的一個(gè)泛化而已。不過免去從Object和其他類型之間不辭辛勞的轉(zhuǎn)型,這就是這個(gè)所謂的“泛型”帶給我們的好處。看起來似乎只是一個(gè)對容器類的新的解決方案而不是其他,不是么?所以這次討論會得到的一致結(jié)論是,這個(gè)所謂的泛型只是解決了容器類之間的自動轉(zhuǎn)型罷了。另外一個(gè)爭論是,如果讓代表的是一種任意類型的話,會引起類型不安全的事件。這顯然不對,因?yàn)镃++能在編譯的時(shí)候捕捉這樣的錯(cuò)誤。“啊哈”,他們說,“那是因?yàn)槲覀儽黄扔昧硗庖环N方法來實(shí)現(xiàn)Java的泛型”。所以Java中的泛型是真正的“自動轉(zhuǎn)型”。這是Java世界的方法,我們將失去真正的泛型(也就是隱式類型,事實(shí)上,我們可以用反射-reflection來實(shí)現(xiàn)這樣的功能,我在我的《Thinking in Java》中做過2,3次這樣的試驗(yàn),但是實(shí)現(xiàn)起來有點(diǎn)亂,失去了Java的文雅本性)。一開始我對Java的泛型有震驚,但是現(xiàn)在過去了。至少有一點(diǎn)清晰的是,這是不得不這樣的。C#雖然有一個(gè)比Java更好的泛型模式(因?yàn)樗麄冇悬c(diǎn)超前,他們修改了底層的IL所致,舉個(gè)例子說,類和類之中的靜態(tài)域(static field)是不一樣的),但是也不支持隱式類型。所以,如果你想用隱式參數(shù),你不得不使用C++或者Python或者Smalltalk,或者Ruby等等:)。

    相關(guān)文章
    對該文的評論
    CSDN 網(wǎng)友 ( 2006-02-24)
    sadf
    ilovevc ( 2004-05-26)
    泛型對java可是一個(gè)新的東西,因此Bruce?Eckel只能參照其他已經(jīng)有的實(shí)現(xiàn),來判斷Java的泛型能力。如果參照C++中的泛型,那么Java現(xiàn)在具有的這個(gè)泛型的能力,大概不會超過在任何一本講泛型的C++書籍上前5頁。沒有trait,police,deduction,template?template?parameter,partial?specialization,基本上也就僅僅能夠解決容器的強(qiáng)制類型轉(zhuǎn)換問題。

    另外,像c++那種意義的泛型,極度依賴編譯器,而不是預(yù)處理程序,預(yù)處理程序只能在文字literal上工作,例如include,macro,ifdef等,而泛型需要處理語法單元,而且這個(gè)過程極度不簡單。至少,C++98標(biāo)準(zhǔn)出來這么多年了,現(xiàn)在市面上還沒有100%符合C++標(biāo)準(zhǔn)的編譯器存在,泛型無疑是其中的一個(gè)技術(shù)難點(diǎn)。C++編譯器的開發(fā)者雖然不見得比Java強(qiáng),但是應(yīng)該不至于差太遠(yuǎn),因此還是有難度的。

    C++的泛型可以產(chǎn)生出一種設(shè)計(jì)模式,我們從面向過程(數(shù)據(jù)和算法分離)到面向?qū)ο螅〝?shù)據(jù)和算法結(jié)合),也許以后就是面向泛型了(數(shù)據(jù)和算法再次分離)。^_^

    marshine ( 2004-05-25)
    TO?SnowFalcon:
    你不覺得你所說的方式不就是目前C#使用的方式嗎?只是表示方法不一樣罷了。而且總的來說討論的是Generic,它的價(jià)值并不會因?yàn)槭欠裼薪涌谙拗贫ヒ饬x,即便存在Bruce?Eckel所說的問題,也不能說“這可不是范型”,過了。
    Benfish ( 2004-05-24)
    c#泛型比java泛型好像先進(jìn)一些,java中對原始類型還要自動裝箱,而c#中是直接使用原始類型,這樣就提高運(yùn)行效率了
    Benfish ( 2004-05-24)
    怎么大家說來說去就說那一種泛型的應(yīng)用啊。
    其實(shí)泛型給我們提供的東西多著呢!
    比如:
    queue?qint;
    set?sset;
    我覺的這種應(yīng)用才是最能提高效率的。
    c++的泛型是在編譯時(shí)的泛型,比如你要編譯作者提的那個(gè)speak()函數(shù),
    你就必須讓它和class?Dog和class?Robot的源代碼一起編譯
    我想c++stl中提供的模板類也要在使用時(shí)以源代碼提供
    在編譯以后就不存在泛型了,它們都在編譯時(shí)自動轉(zhuǎn)變成了確定的類型
    而在c#中使用Queue是不需要Queue這個(gè)類的源代碼的。

    而且java,?c#都是強(qiáng)類型的,像文章中舉的那個(gè)speak()函數(shù)的例子就
    不符合強(qiáng)類型的精神,所以不可能在java或者c#中實(shí)現(xiàn)的。
    但是這并不是數(shù)它們就必c++弱
    像c++那種意義的泛型
    任何語言都可以簡單的在編譯器上加上一個(gè)預(yù)處理程序來實(shí)現(xiàn)
    這和運(yùn)行的是什么架構(gòu)沒有任何關(guān)系,僅僅是一個(gè)編譯問題

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


    網(wǎng)站導(dǎo)航:
     
    主站蜘蛛池模板: 丝袜足液精子免费视频| 久草视频在线免费| 亚洲午夜电影在线观看高清| 在线观看免费a∨网站| 中文字幕无码毛片免费看| 亚洲人成在线播放| 亚洲福利视频一区二区| 亚洲成年人免费网站| 人妻18毛片a级毛片免费看| 噜噜噜亚洲色成人网站∨| 免费v片在线观看无遮挡| 无码人妻久久一区二区三区免费 | 亚洲av乱码中文一区二区三区| 久久久青草青青国产亚洲免观| 精品免费久久久久久久| a免费毛片在线播放| 亚洲色偷偷色噜噜狠狠99网| 亚洲AV无码乱码在线观看富二代 | 四虎永久在线精品免费网址| 国产精品偷伦视频免费观看了| 亚洲av成人一区二区三区| 亚洲真人无码永久在线| 女人张腿给男人桶视频免费版| 国产情侣久久久久aⅴ免费| 国产成人亚洲午夜电影| 亚洲国产超清无码专区| 亚洲综合色自拍一区| 国产一区二区三区免费视频| 最近中文字幕大全中文字幕免费| 成年网站免费入口在线观看| 亚洲日韩AV一区二区三区四区 | 成人爱做日本视频免费| 成人免费视频网站www| 中文精品人人永久免费 | 免费无码又爽又刺激高潮| 18成禁人视频免费网站| 好紧我太爽了视频免费国产| 看一级毛片免费观看视频| 亚洲综合色丁香婷婷六月图片| 亚洲日本在线播放| 亚洲AV成人片色在线观看高潮|