我的隱式生活(My Implicit Life)

          繼續(xù)搞“對(duì)象”,玩OO.

          首頁 新隨筆 聯(lián)系 聚合 管理
            11 Posts :: 1 Stories :: 39 Comments :: 0 Trackbacks

          2006年7月15日 #

          近期寫了個(gè)電子書的C/S模式的下載工具,一個(gè)server端,一個(gè)client端。

          目的就是想在公司能很方便的訪問家里那些收集很久電子書,方便查閱。

          用了1,2個(gè)星期,雖然寫的很爛,但是沒有用任何第三方的產(chǎn)品(server or db)。

          現(xiàn)在里面的書籍已經(jīng)接近200本了。

          注:server就用了家里的adsl,所以速度慢,關(guān)閉不定時(shí)。畢竟玩玩嘛。

          有興趣的朋友先裝個(gè)jdk1.5。再運(yùn)行下面壓縮包里的exe文件執(zhí)行即可。

          點(diǎn)此下載

          User ID:???????????????blogjava
          Password:???????????? blogjava
          ?

          posted @ 2006-10-15 13:21 marco 閱讀(3476) | 評(píng)論 (9)編輯 收藏

          Java Collection Framwork中的類的確是最重要的基礎(chǔ)api,實(shí)現(xiàn)任何算法,基本上都很難離開它。

          因此理解這堆“集合(Collection)類”很有必要。聲明一下,以前一直都是叫它們集合類,但是好像Think In Java的作者鄙視了這個(gè)說法,嚴(yán)格的說應(yīng)該叫Container類,而后看了它整整一章書以后,覺得還是人家說的有道理。

          它說這個(gè)container類庫,包含了兩大類,Collection和Map,而Collection又可以分為List和Set。當(dāng)然這些抽象概念都被定義成了接口。

          話說,這樣的分類的確是嚴(yán)格按照類之間的繼承關(guān)系來說得,但是俺總覺得很別扭,真動(dòng)手的時(shí)候,還是很難選擇。當(dāng)然,Anytime and Anywhere使用ArrayList絕對(duì)都能解決問題,但這樣做畢竟太農(nóng)民了一點(diǎn)。

          所以,我自己有了一些想法。先回歸到最基本最基本的數(shù)據(jù)結(jié)構(gòu)的層面,管你是Collection還是Container,反正描述的都是一堆東西吧。數(shù)據(jù)結(jié)構(gòu)第一章講了一個(gè)結(jié)構(gòu):在物理上連續(xù)分配空間的順序結(jié)構(gòu),叫順序表(希望記性是好的),而離散分配空間的,應(yīng)該叫做鏈表,最常用的就是單鏈表。這兩個(gè)東西,其實(shí)就是很多復(fù)雜數(shù)據(jù)結(jié)構(gòu)的基礎(chǔ),還記得嗎,當(dāng)時(shí)就是講完這些東西,才開始講棧、隊(duì)列、二叉樹、有向無向圖的。所以,這個(gè)順序結(jié)構(gòu)是很基礎(chǔ)的。而在JAVA中,順序表對(duì)應(yīng)的就是List接口,而一般順序表就是ArrayList(有效進(jìn)行隨機(jī)index查找);而單鏈表就是LinkedList(有效進(jìn)行插入和刪除),兩個(gè)的優(yōu)劣當(dāng)年都講爛了,這里就不說了。

          有了這兩個(gè)結(jié)構(gòu)以后,JAVA就不提供Stack和Queue單獨(dú)的類了,因?yàn)椋脩艨梢杂蒙厦鎯蓚€(gè)類輕易的去實(shí)現(xiàn)。

          那Set和Map有怎么跟List連上關(guān)系呢?

          我認(rèn)為可以把它們看成是無序和單一的List(Map只是兩個(gè)有映射關(guān)系的List罷了)。

          Set和Map無序和單一的特性,決定了它們天大的需求就是根據(jù)關(guān)鍵字(元素對(duì)象)檢索。so,為了效率,必須hash。

          有了HashSet和HashMap。

          同時(shí),如果非要保持住元素的順序,有了LinkedHashSet、LinkedHashMap。


          結(jié)論:

          假如你的需求是
          1:往Container中放的對(duì)象是無序且單一的;
          2:經(jīng)常要檢索。
          用HashSet或HashMap吧。

          ps:這兩個(gè)條件其實(shí)是一回事,因?yàn)槿绻遣粏我坏脑挘闳z索它干嘛。

          如果進(jìn)而需要保持元素的順序,不要讓他順便iteration,那就選擇LinkedHashSet和LinkedHashMap。

          假如你的需求不滿足以上1&2,那你放心,List肯定能幫你解決,你只要稍微想一下是ArrayList好還是LinkedList好。

          題外話:

          關(guān)于Hash,務(wù)必記得要讓自己的元素對(duì)象override hashCode()和 equles() 方法,要不你直接可以洗了睡。

          關(guān)于所有這些Container,務(wù)必記得有個(gè)輔助類叫Interator,遍歷盡量要用它。

          關(guān)于一些老的Stack、Vector、HashTable,聽說以后不要用了哦。收到啦!!

          posted @ 2006-09-20 16:53 marco 閱讀(2330) | 評(píng)論 (0)編輯 收藏

          任何信息,基本都是以文字的形式傳播和記錄下來的。

          在計(jì)算機(jī)中,文字就是字符的集合,也就是字符串,C就是因?yàn)閷?duì)字符串設(shè)計(jì)的不好,才那么容易溢出。而別的一些高級(jí)語言,對(duì)于這個(gè)進(jìn)行了很多的改進(jìn)。

          編程的人由于技術(shù)方向和應(yīng)用方向的不同,日常編程的內(nèi)容差距很大。但是對(duì)于字符串的處理,那可是永遠(yuǎn)都避不開的工作。

          昨天跑步的時(shí)候,想了一下,對(duì)于字符串的操作有那么多(search,match,split,replace),感覺很煩雜,能不能抓住這些操作的一個(gè)基本集?

          不知道對(duì)不對(duì),反正想出來了一個(gè),這個(gè)基本操作就是search,這里的search的意思是:在輸入串中找到目標(biāo)串的開始位置(start index),和結(jié)束位置(end index)。

          有了這個(gè)基本集,別的操作都很好衍生出來:

          局部match:其實(shí)就是要求search操作至少返回一個(gè)start index。

          全match:其實(shí)要求search操作的至少返回一個(gè)start index,并且start index要為零,end index要為輸入串的全長。

          split:其實(shí)就是search操作之后,把前一個(gè)end index和當(dāng)前的start index之間的字符串截出來而已。

          replace:其實(shí)就是search操作之后,把start index和end index之間的字符串換成另外的而已。

          所以,歸根到底,都是一個(gè)search操作的拓展罷了。這么一想,感覺清晰多了。

          這么一來,API對(duì)search的能力支持的好壞和效率高低是衡量字符串操作功能的標(biāo)準(zhǔn),當(dāng)然,如果有直接支持match,split,replace操作的話就更好了。

          java對(duì)字符串search的支持,最基本的就是下面的String的indexOf方法:

          int indexOf(String str)
          ????????? Returns the index within this string of the first occurrence of the specified substring.

          這里我想說的是,很多時(shí)候我們所謂要search的目標(biāo)串,根本就不是固定單一的,而是變化多樣的。如果只有一兩種情況,最多用兩次上面的方法唄。但是有些情況是近乎不可能羅列的,例如,我們講的代表email的字符串,我們不可能遍歷它吧。

          所以,需要一種能夠通用表達(dá)字符串格式的語言。這就是Regular Expression(re)。

          假如上面方法indexOf的str參數(shù)能支持re做為參數(shù)的話,那對(duì)于這種多樣的search也可以用上面的方法了。

          可惜,indexOf不支持re作為參數(shù)。

          so,以下就介紹java api中可以用re作為參數(shù)的字符串操作方法(參數(shù)中的regex就是re)。

          --------------------->>
          String類的:

          全match操作:
          boolean matches(String regex)
          ????????? Tells whether or not this string matches the given regular expression.

          全replace操作:
          String replaceAll(String regex, String replacement)
          ????????? Replaces each substring of this string that matches the given regular expression with the given replacement.

          首個(gè)replace操作:
          String replaceFirst(String regex, String replacement)
          ????????? Replaces the first substring of this string that matches the given regular expression with the given replacement.

          全split操作:
          String[] split(String regex)
          ????????? Splits this string around matches of the given regular expression.


          有限制數(shù)的split操作:
          String[] split(String regex, int limit)
          ????????? Splits this string around matches of the given regular expression.

          <<---------------------

          可惜啊,可惜,可惜java的String類里面沒有可以支持re的search方法,那如果要用re來search,只好使用java中專門的re類庫。

          java中的re類庫主要就兩個(gè)類,一個(gè)叫Pattern,顧名思義,代表re的類。一個(gè)叫Matcher類,反映當(dāng)前match狀況的類(如存放了當(dāng)前search到的位置,匹配的字符串等等信息)。

          一般在構(gòu)造中,“re的表達(dá)式”作為參數(shù)傳遞入Pattern類,“輸入串(待過濾串)”作為參數(shù)傳遞入Matcher類。

          然后使用Matcher類的字符串search方法就可以了。Matcher真正提供search功能的API叫find。下面列出。
          --------------------->>
          Matcher類search操作相關(guān)的方法:

          boolean lookingAt()
          ????????? Attempts to match the input sequence, starting at the beginning, against the pattern.

          boolean matches()
          ????????? Attempts to match the entire input sequence against the pattern.

          boolean find()
          ????????? Attempts to find the next subsequence of the input sequence that matches the pattern.

          String group()
          ????????? Returns the input subsequence matched by the previous match.

          <<---------------------

          前三個(gè)都是search方法,返回成功與否。第四個(gè)是返回當(dāng)前search上的字符串。

          ok,至此。使用re的search操作也有眉目了。

          當(dāng)然,Pattern和Matcher也包含直接使用re進(jìn)行的match,split,replace操作。

          --------------------->>
          Patter類別的字符串操作方法

          全match操作:
          static boolean matches(String regex, CharSequence input)
          ????????? Compiles the given regular expression and attempts to match the given input against it.

          全split操作:
          String[] split(CharSequence input)
          ????????? Splits the given input sequence around matches of this pattern.

          有限制數(shù)的split操作:
          String[] split(CharSequence input, int limit)
          ????????? Splits the given input sequence around matches of this pattern.


          Matcher類別的字符串操作方法

          全replace操作:
          String replaceAll(String replacement)
          ????????? Replaces every subsequence of the input sequence that matches the pattern with the given replacement string.

          首個(gè)replace操作:
          String replaceFirst(String replacement)
          ????????? Replaces the first subsequence of the input sequence that matches the pattern with the given replacement string.

          動(dòng)態(tài)replace(replacement可以根據(jù)被替代的字符串變化而變化)
          Matcher appendReplacement(StringBuffer sb, String replacement)
          ????????? Implements a non-terminal append-and-replace step.

          StringBuffer appendTail(StringBuffer sb)
          ????????? Implements a terminal append-and-replace step.

          <<---------------------

          總結(jié):
          當(dāng)必須使用re的時(shí)候,search操作就要用到Pattern,Matcher,當(dāng)然動(dòng)態(tài)的replace操作也要用到這兩個(gè)類。而別的match,replace,split操作,可以使用pattern,Matcher,當(dāng)然也可以直接使用String,推薦還是用回咱們的String吧。

          注:以上都是看jdk1.4以上的文檔得出的結(jié)論,以前版本不能用不負(fù)責(zé)任。

          posted @ 2006-08-31 15:13 marco 閱讀(2696) | 評(píng)論 (0)編輯 收藏

          創(chuàng)建和銷毀對(duì)象

          重點(diǎn)關(guān)注對(duì)象的創(chuàng)建和銷毀:什么時(shí)候、如何創(chuàng)建對(duì)象,什么時(shí)候、什么條件下應(yīng)該避免創(chuàng)建對(duì)象,如何保證對(duì)象在合適的方式下被銷毀,如何在銷毀對(duì)象之前操作一些必須的清理行為。

          嘗試用靜態(tài)工廠方法代替構(gòu)造器

          如果一個(gè) client 要實(shí)例化一個(gè)對(duì)象來使用,傻 b 都知道應(yīng)該先調(diào)用類的構(gòu)造器來 new 一個(gè)對(duì)象,之后再調(diào)用相應(yīng)的方法。除了這個(gè)方式, Java Effective 還建議了另一種方法:用靜態(tài)工廠方法來提供一個(gè)類的實(shí)例。以下的例子不反映兩者的優(yōu)劣,只是反映兩者在代碼實(shí)現(xiàn)上的不同,優(yōu)劣之后再談:

          假設(shè)咱們要一個(gè)顏色為黑色、長度為 50cm 的錘子,自然就用構(gòu)造器創(chuàng)建一個(gè)

          Hammer myHammer =? new Hammer(Color.BLACK, 50);

          而用靜態(tài)工廠方法來實(shí)例化一個(gè)對(duì)象,如下

          Hammer myHammer = Hammer.factory(Color.BLACK,50);

          也可以用專門的一個(gè)工廠類來實(shí)例化

          Hammer myHammer = Toolkit.factory(“Hammer”, Color.BLACK,50);??

          單純從上面的代碼上看,真的只有傻 b 才會(huì)選擇靜態(tài)工廠的方法,完全就是多此一舉,直接 new 又快又爽,搞這么麻煩做莫斯(武漢話“什么”的意思)?

          別急,別急,你急個(gè)莫 b (武漢粗話:基本就是“你急個(gè)毛”的意思)?

          下面就說說用靜態(tài)工廠代替構(gòu)造器的好處( advantage )和不好處( disadvantage )。

          第一個(gè)好處,講你都不信,行家們認(rèn)為,構(gòu)造器有一個(gè)不好的地方就是:這個(gè)方法的簽名( signture )太固定了。

          構(gòu)造器的名字是固定的,生個(gè) Hammer ,構(gòu)造器的名字就是 Hammer (……),唯一能變化的地方就是參數(shù),假設(shè)我的這個(gè)錘子有兩個(gè)很變態(tài)的構(gòu)造需要:

          1 :第一個(gè)參數(shù)是顏色( Color 型),第二個(gè)參數(shù)是錘子頭的重量( int 型)。

          Hammer Color c, int kg {

          //remainder omited

          }

          2 :第一個(gè)參數(shù)是顏色( Color 型),第二個(gè)參數(shù)是錘子的長度( int 型)。

          Hammer Color c, int cm {

          //remainder omited

          }

          感覺滿足需要了,但是細(xì)心一看,完了,構(gòu)造器的參數(shù)列表類型重復(fù)了,肯定編譯通不過,這是面向?qū)ο髽?gòu)造器天生的缺陷——唯一的變化就是參數(shù),參數(shù)都分辨不了,就真的分辨不了。

          而另外就算參數(shù)能分辨的了,構(gòu)造器一多,它的參數(shù)一多,您根本就不知道每個(gè)參數(shù)是用來干什么的,只能去查閱文檔,在您已經(jīng)眼花繚亂的時(shí)候再去查文檔,一個(gè)一個(gè)的對(duì),折磨人的活。

          這個(gè)時(shí)候,您就可以考慮用靜態(tài)工廠方法來實(shí)例化對(duì)象了。因?yàn)殪o態(tài)工廠方法有一個(gè)最簡單的特點(diǎn)就是:他有可以變化的方法名(構(gòu)造器的名字變不了)。用名字的不同來代表不同的構(gòu)造需要,這么簡單的普通的特點(diǎn)在這里就是它相對(duì)于構(gòu)造器的 advantage

          如上面的錘子的例子可以這樣:

          1 Hammer.produceByWeight (Color c, int kg){

          //remainder omited

          }

          2 Hammer.produceByHeight (Color c, int cm){

          //remainder omited

          }

          這是不是一目了然多了。嗯,我是這樣認(rèn)為的。

          第二個(gè)好處,“靜態(tài)工廠方法不需要每次都真的去實(shí)例化一個(gè)對(duì)象”——其實(shí)這也是另一些優(yōu)化方法的前提。

          構(gòu)造器的每次 invoke 必定會(huì)產(chǎn)生一個(gè)新的對(duì)象,而靜態(tài)工廠方法經(jīng)過一定的控制,完全可以不用每次 invoke 都生成一個(gè)新的對(duì)象。

          為什么不每次都生成一個(gè)對(duì)象的原因就不必說了,因?yàn)樵蛱黠@。這個(gè)原因就是為什么要“共享”對(duì)象的原因。

          下面講講通常使用的兩種共享具體策略,也就是具體方法了:

          1 :單例模式的需要,一旦需要某個(gè)對(duì)象有單例的需要,必定對(duì)于這類對(duì)象的構(gòu)造只能用靜態(tài)工廠方法了。

          2 flyweight 模式和不變( immutable 模式的需要,這兩個(gè)模式很多時(shí)候都說一起使用的,一旦一些對(duì)象我們認(rèn)為是不變的,那自然就想拿來重用,也就說共享,而 flyweight 就是用來重用這些小粒度對(duì)象的。

          Boolean.valueOf (boolean) 方法:

          Boolean a = Boolean.valueOf (100);

          Boolean b = Boolean.valueOf (100);

          ?a,??b兩個(gè)引用都是指向同一個(gè)對(duì)象。

          這些對(duì)象都是不變的,而 valueOf 的控制就是用的 flyweight 方法。

          這種一個(gè)狀態(tài)(如上面一個(gè)數(shù)字)對(duì)應(yīng)的對(duì)象只有一個(gè)還有一個(gè)好處,就是可以直接通過比較“引用”來判斷他們是否 equel (這里的 equel 是邏輯相等的意思),以前需要 a.equels(b) ,而一旦用“ flyweight 模式和不變( immutable 模式”后,避免了產(chǎn)生多余的相同對(duì)象,用 a==b 就可以達(dá)到 a.equels(b) 的目的了。這樣當(dāng)然優(yōu)化了 performance ??

          第三個(gè)好處,其實(shí)就是工廠方法的核心好處——我把它稱為“抽象類型構(gòu)造器”。它可以為我們提供一個(gè)抽象類型的實(shí)例,同時(shí)必要的隱藏了抽象類型的具體結(jié)構(gòu)。這是 new 怎么都達(dá)不到的。

          這種模式的好處其實(shí)就是面向?qū)ο蟮淖詈诵牡暮锰帲橄蠛途唧w可以分離,一旦抽象定義好了,具體的東西可以慢慢的變化,慢慢的拓展——開閉原則。

          Collections Framework API ,都是描述集合類型的接口,也就是對(duì)于客戶端來看,只有 Collection 這個(gè)類要認(rèn)識(shí),而實(shí)際上,實(shí)現(xiàn)這個(gè)接口的 Collection 是多種多樣的。如果要讓用戶都知道這些具體實(shí)現(xiàn)的 Collection ,就增加了復(fù)雜度。

          這時(shí),通過一個(gè)靜態(tài)工廠方法,就可以隱藏各種 Collection 的具體實(shí)現(xiàn),而讓 Client 只使用返回的 Collection 對(duì)象就可以了。

          這里還可以加上一些權(quán)限控制,如這些實(shí)現(xiàn)只要對(duì)于工廠來講是可以訪問的,不用是 public 的,而他們只要通過 public 的工廠就可以提供給用戶。非常有利于代碼的安全。

          靜態(tài)工廠方法的第一個(gè)缺點(diǎn)就是:使用靜態(tài)工廠方法創(chuàng)建的類的構(gòu)造器經(jīng)常都是非公共或非 protected 的。 這樣,以后這些類就沒有辦法被繼承了。不過也有人說,不用繼承就用 composition 唄。也是!呵呵。

          靜態(tài)工廠方法的第二個(gè)缺點(diǎn)是:在 jdk 文檔里,這些靜態(tài)工廠方法很難跟別的靜態(tài)方法相區(qū)別。 而文檔中,構(gòu)造器是很容易看到的。

          為了一定程度解決這個(gè)問題,我們可以用一些比較特別的名字來給這類靜態(tài)工廠方法來命名。最常用的有:

          valueOf —— 用來放回跟參數(shù)“相同值”的對(duì)象。

          getInstance —— 返回一個(gè)對(duì)象的實(shí)例。單例模式中,就是返回單例對(duì)象。

          總結(jié):靜態(tài)工廠方法和構(gòu)造器都有各自的特點(diǎn)。最好在考慮用構(gòu)造器之前能先考慮一下靜態(tài)工廠方法,往往,后者更有用一點(diǎn)。如果權(quán)衡了以后也看不出那個(gè)好用一些,那就用構(gòu)造器,畢竟簡單本分多了。

          posted @ 2006-07-15 12:35 marco 閱讀(632) | 評(píng)論 (0)編輯 收藏

          主站蜘蛛池模板: 同江市| 余干县| 湟中县| 周宁县| 香港| 新疆| 丁青县| 崇明县| 微山县| 类乌齐县| 承德县| 台中县| 综艺| 清镇市| 惠水县| 隆安县| 彭州市| 余江县| 巴林右旗| 伊宁市| 富裕县| 永川市| 大庆市| 澄迈县| 任丘市| 汝南县| 保定市| 祁阳县| 大庆市| 杨浦区| 竹山县| 灵山县| 千阳县| 陕西省| 凤山市| 平塘县| 广南县| 万州区| 娄底市| 辉县市| 巴彦淖尔市|