<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)航:
     
    主站蜘蛛池模板: 免费看搞黄视频网站| 亚洲一级毛片免费观看| 深夜福利在线免费观看| 免费看大黄高清网站视频在线| 国产精品亚洲片夜色在线| 欧洲乱码伦视频免费| 亚洲国色天香视频| 永久免费av无码网站韩国毛片| 亚洲一级大黄大色毛片| 成年人在线免费看视频| 亚洲国产高清国产拍精品| 在线免费观看毛片网站| 美女黄频免费网站| 亚洲日韩精品无码专区网站| 一个人看www免费高清字幕| 亚洲精品乱码久久久久久| 在线观看免费播放av片| 亚洲性色高清完整版在线观看| 好男人视频在线观看免费看片| 黄色免费网址在线观看| 国产亚洲人成网站观看| 免费A级毛片无码A∨免费| 亚洲AV无码一区二区三区牛牛| 免费国产a国产片高清| 国产免费久久精品丫丫| 91亚洲va在线天线va天堂va国产| 免费看黄视频网站| 美女裸免费观看网站| 亚洲AV永久精品爱情岛论坛| aⅴ免费在线观看| 日韩精品亚洲专区在线影视| 亚洲一区二区三区在线观看精品中文| 久久中文字幕免费视频| 亚洲乱码无人区卡1卡2卡3| 亚洲免费无码在线| 国产精品视频免费| 一级A毛片免费观看久久精品| 无码乱人伦一区二区亚洲| 免费看AV毛片一区二区三区| 成全视频免费观看在线看| 亚洲日本一线产区和二线产区对比|