第六條 在改寫equals的時候請遵守通用規(guī)定
            有一種“值類”可以不要求改寫equals方法,類型安全枚舉類型,因為類型安全枚舉類型保證每一個值之多只存在一個對象,所有對于這樣的類而言,Object的queals方法等同于邏輯意義上的equals方法。
           
            在改寫equals方法的時候,要遵循的規(guī)范: 
                  1,自反性。對任意的引用值x,x.equals(x)一定是true
                  2,對稱性。對于任意的引用值x和y,當(dāng)且僅當(dāng)y.equals(x)返回true時,x.equals(y)也一定返回true.
                  3,傳遞性。對于任意的引用值x,y和z,如果x.equals(y)==true and y.equals(z)==true,so x.equals(z)==true.
                  4,一致性。對于任意的引用值x和y,如果用于equals比較的對象信息沒有被修改的話,那么,多次調(diào)用x.equals(y)要么一致地返回true,要么一致地返回false.
                  5,非空性。對于任意的非空引用值x,x.equals(null)一定返回false.
                  
            自反性:要求一個對象必須等于其自身。一個例子:你把該類的實例加入到一個集合中,則該集合的contains方法
          將果斷地告訴你,該集合不包含你剛剛加入的實例. 

            對稱性:
            例如:
               public final class CaseInsensitiveString{
                     private String s;
                     public CaseInsensitiveString(String s){
                        if(s==null)   throw new NullPointerException();
                        this.s=s;
                     }
                     public boolean equals(Object o){
                        if(o instanceof CaseInsensitiveString)
                           return s.equalsIgnoreCase(((CaseInsensitiveString)o).s);
                        if(o instanceof String)
                           return s.equalsIgnoreCase((String)o);
                         return false;
                      }
                    }
          調(diào)用:
             CaseInsensitiveString cis=new CaseInsensitiveString("Polish");
                 String s="polish";
          正如我們期望的:cis.equals(s)==true but s.equals(cis)==false
          這就違反了對稱性的原則.為了解決這個問題,只需把企圖與String互操作的這段代碼從equals方法中去掉舊可以了.這樣做之后,你可以重構(gòu)代碼,使他變成一條返回語句:
          public boolean equals(Object o){
             return o instanceof CaseInsensitiveString && ((CaseInsensitiveString)o).s.equalsIgnoreCase(s);
          }

           

          傳遞性---即如果一個對象等于第二個對象,并且第二個對象又等于第三個對象,則第一個對象一定等于第三個對象。
          例如:
                 public class Point{
                     private final int x;
                     private final int y;
                     public Point(int x,int y){
                          this.x=x;
                          this.y=y;
                    }
                    public boolean equals(Object o){
                       if(!(o instanceof Point))
                        return false;
                       Point p=(Point)o;
                       return p.x==x&&p.y==y;
                    }
               }
          現(xiàn)在我們來擴展這個類,為一個點增加顏色信息:
             public class ColorPoint extends Point{
                private Color color;
                public ColorPoint(int x,int y,Color color){
                    super(x,y);
                    this.color=color;
                }
             }
          分析: equals方法會怎么樣呢?如果你完全不提供equals方法,而是直接從Point繼承過來,那么在equals座比較的時候顏色信息會被忽略掉。如果你編寫一個equals方法,只有當(dāng)實參是另一個有色點,并且具有同樣的位置和顏色的時候,它才返回true:
                 public boolean equals(Object o){
                    if(!(o instanceof ColorPoint)) return false;
                    ColorPoint cp=(ColorPoint)o;
                    return super.equals(o) && cp.color==color;
                 }
          分析:這個方法的問題在于,我們在比較一個普通點和一個有色點,以及反過來的情形的時候,可能會得到不同的結(jié)果。前一種比較忽略了顏色信息,而后一種比較總是返回false,因為實參的類型不正確。例如:
               Point p=new Point(1,2);
               ColorPoint cp=new ColorPoint(1,2,Color.RED);
          然后:p.equals(cp)==true but cp.equals(p)==false

          修正:讓ColorPoint.equals在進行“混合比較”的時候忽略顏色信息:
             public boolean equals(Object o){
                 if(!(o instanceof Point)) return false;
                 if(!(o instanceof ColorPoint)) return o.equals(this);
                 ColorPoint cp=(ColorPoint)o;
                 return super.equals(o) && cp.color==color;
             }
          這種方法確實提供了對稱性,但是卻犧牲了傳遞性:
             ColorPoint p1=new ColorPoint(1,2,Color.RED);
             Point p2=new Point(1,2);
             ColorPoint p3=new ColorPoint(1,2,Color.BLUE);
          此時:p1.equals(p2)==true and p2.equals(p3)==true but p1.equals(p3)==false很顯然違反了傳遞性。前兩個比較不考慮顏色信息,而第三個比較考慮了顏色信息。

          結(jié)論:要想在擴展一個可實例華的類的同時,既要增加新的特征,同時還要保留equals約定,沒有一個簡單的辦法可以做到這一點。根據(jù)"復(fù)合優(yōu)于繼承",這個問題還是有好的解決辦法:我們不讓ColorPoint擴展Point,而是在ColorPoint中加入一個私有的Point域,以及一個公有的視圖方法,此方法返回一個與該有色 點在同一位置上的普通Point對象:
              public class ColorPoint{
                 private Point point;
                 private Color color;
                 public ColorPoint(int x,int y,Color color){
                   point=new Point(x,y);
                   this.color=color;
                 }
                 public Point asPoint(){
                     return point;
                 }
               
                 public boolean equals(Object o){
                     if(!(o instanceof ColorPoint)) return false;
                     ColorPoint cp=(ColorPoint)o;
                     return cp.point.equals.(point) && cp.color.equals(color);
                 }
              }
             
          注意,你可以在一個抽象類的子類中增加新的特征,而不會違反equals約定。

           

          一致性:
           如果兩個對象相等的話,那么它們必須始終保持相等,除非有一個對象被修改了。由于可變對象在不同的時候可以與不同的對象相等,而非可變對象不會這樣,這個約定沒有嚴(yán)格界定。
           


          非空性:沒什么好說的。

          1,使用==操作符檢查“實參是否為指向?qū)ο蟮囊粋€應(yīng)用”。如果是的話,則返回true。
                 2,使用instanceof操作符檢查“實參是否為正確的類型”。如果不是的話,則返回false。
                 3,把實參轉(zhuǎn)換到正確的類型。
                 4,對于該類中每一個“關(guān)鍵(significant)”域,檢查實參中的域與當(dāng)前對象中對應(yīng)的域值是否匹配
               if (!(this.field == null ? o.field == null : this.equals(o.field)))
               //或者寫成 if(!(this.field == o.field || (this.field != null && this.field.equals(o.field)))) 對于this.field和o.field通常是相同的對象引用,會更快一些。
                 return false;
               //比較下一個field
               //都比較完了
               return true;
               
          5.最后還要確認(rèn)以下事情
             5.1)改寫equals的同時,總是(必須)要改寫hashCode方法(見【第8條】),這是極容易被忽略的,有極為重要的
             5.2)不要企圖讓equals方法過于聰明
             5.3)不要使用不可靠的資源。如依賴網(wǎng)絡(luò)連接
             5.4)不要將equals聲明中的Object對象替換為其他類型。
                   public boolean equals(MyClass) 這樣的聲明并不鮮見,往外使程序員數(shù)小時搞不清楚為什么不能正常工作
                   原因是這里是重載(overload)而并不是改寫(override)(或稱為覆蓋、重寫)
                   相當(dāng)于給equals又增加了一個實參類型為MyClass的重載,而實參為Object的那個equals并沒有被改寫,依然還是從Object繼承來的最初的那個equals,所總是看不到程序員想要的效果。因為類庫或其他人寫的代碼都是調(diào)用實參為Object型的那個equals方法的(別人又如何在事前知曉你今天寫的MyClass呢?)

          posted @ 2009-07-28 20:30 胡鵬 閱讀(227) | 評論 (0)編輯 收藏
           

          ExtJS可以用來開發(fā)RIA也即富客戶端的AJAX應(yīng)用,是一個用javascript 的,主要用于創(chuàng)建前端用戶界面,是一個與后臺技術(shù)無關(guān)的前端ajax框架。因此,可以把ExtJS用在.NetJavaPhp等各種開發(fā)語言開發(fā)的應(yīng) 用中。

          ExtJs最開始基于YUI技術(shù),由開發(fā)人員Jack Slocum開發(fā),通過參考Java Swing等機制來組織可視化組件,無論從UI界面上CSS樣式的應(yīng)用,到數(shù)據(jù)解析上的異常處理,都可算是一款不可多得的JavaScript客戶端技術(shù) 的精品。

          ExtJS:    http://www.spket.com/demos/js.html spket插件(eclipse)

          ·         Start Aptana and navigate the application menu to: Help → Software Updates → Find and Install… → Search for new features to install → New remote site…

          ·         Name: “Spket”, Url: “http://www.spket.com/update/

          ·         Restart Eclipse

          ·         Watch this Spket IDE Tutorial to see how to easily add Ext code assist (you can point it at the latest /src/ext.jsb to keep code assist up to date with the latest Ext version). The steps are basically:

          o    Window → Preferences → Spket → JavaScript Profiles → New

          o    Enter “ExtJS” and click OK

          o    Select “ExtJS” and click “Add Library”, then choose “ExtJS” from the dropdown

          o    Select “ExtJS” and click “Add File”, then choose the “ext.jsb” file in your “./ext-2.x/source” directory

          o    Set the new ExtJS profile as the default by selecting it an clicking the “Default” button on the right-hand side of the “JavaScript Profiles” dialog.

          o    Restart Eclipse

          o    Create a new JS file and type: Ext. and you should get the Ext Code completion options.

          一個簡單的例子:

          http://extjs.org.cn/node/83

          posted @ 2009-07-26 22:28 胡鵬 閱讀(266) | 評論 (0)編輯 收藏
          java程序設(shè)計風(fēng)格:(類的說明介紹)
              

          Java文件注釋頭

          類中開頭處插入如下 注釋

          /******************************************************************

           *該類功能及特點的描述(例如:該類是用來.....)

           *

           *

               *該類未被編譯測試過。

               *

               *@see(與該類相關(guān)聯(lián)的類):(AnotherClass.java)

               *

               *

           *

           *開發(fā)公司或單位:XXX軟件有限公司研發(fā)中心

           *

           *版權(quán):本文件版權(quán)歸屬XXX公司研發(fā)中心

           *

           *

                 *@author(作者):XXX

                 *

                 *@since(該文件所支持的JDK版本):Jdk1.3Jdk1.4

                 *

                 *@version(版本):1.0

                 *

           *

           *@date(開發(fā)日期):      1999-01-29

           *

           *最后更改日期:        2003-01-02

           *

           *

           *修改人:    XXXX

           *

           *復(fù)審人:    張三李四 王五

           *

           */



          內(nèi)存管理


           

          伊甸園用來保存新的對象,它就像一個堆棧,新的對象被創(chuàng)建,就像指向該棧的指針在不斷的增長一樣,當(dāng)伊甸園區(qū)域中的對象滿了之后,JVM系統(tǒng)將要做可到達性測試,主要任務(wù)是檢測有哪些對象由根集合出發(fā)是不可到達的,這些對象就可以被JVM回收,并且將所有的活動對象從伊甸園區(qū)域拷到TO區(qū)域,此時一些對象將發(fā)生狀態(tài)交換,有的對象就從TO區(qū)域被轉(zhuǎn)移到From區(qū)域,此時From區(qū)域就有了對象,這個過程都是JVM控制完成的。

          Java 中的析構(gòu)方法 finalize

           對象是使用完了 盡量都賦 null

          共享靜態(tài)變量存儲空間

          不要提前創(chuàng)建對象

              ........

              void f(){

                 int i;

                 A a = new A();

                 //A的對象a被創(chuàng)建

                 //在判斷語句之中沒有

                 //應(yīng)用過a對象

                 .....

                 if(....){

                     //A的對象a僅在此處被應(yīng)用

                     a.showMessage();

                     ....

                 }

                 .....

              }

              ..........

             

             

             

              正確的書寫方式為:

              void f(){

                 int i;

                 .....

                 if(...){

                     A a = new A();

                     //A的對象a被創(chuàng)建

                     //應(yīng)用過a對象

                     a.showMessage();

                 }

                 ......

              }

          JVM內(nèi)存參數(shù)調(diào)優(yōu)


          表達式、語句和保留字

          非靜態(tài)方法中可引用靜態(tài)變量

          靜態(tài)方法不可以引用非靜態(tài)變量

          靜態(tài)方法中可 創(chuàng)建 非靜態(tài)變量

          調(diào)用父類的構(gòu)造方法必須將其放置子類構(gòu)造方法的第一行



          JAVA核心類與性能優(yōu)化

          線程同步:Vector Hashtable

          非線程同步: ArrayList HashMap

           

          字符串累加 盡量使用 StringBuffer  += 

          方法length() length屬性  區(qū)別

           

          IO緩存,讀寫文件優(yōu)化。


          類與接口
           

                 內(nèi)部類(Inner Class)是Java語言中特有的類型,內(nèi)部類只能被主類以外的其他內(nèi)部類繼承,主類是不能繼承其內(nèi)部類的,因為這樣就引起了類循環(huán)繼承的錯誤,下面的代碼就是錯誤的。

                 public class A extends x {

                        public A(){}

                        ……

                     Classs x{

                               …..

          }

          }

          上面的代碼將引發(fā)類循環(huán)繼承的錯誤,這種錯誤在編譯時就會被發(fā)現(xiàn),比較容易發(fā)現(xiàn)和排除。

          但是下面例子中的內(nèi)部類的繼承方式卻是正確的:

          class A{

                 ….

                 public  A(){}

                 ……

                 class  X  extends Y  {

                 ……….

          }

                 calss  Y {

                 ……

          }

          }

          什么時候使用繼承,什么樣的繼承是合理的:

          1.       現(xiàn)實世界的事物繼承關(guān)系,可以作為軟件系統(tǒng)中類繼承關(guān)系的依據(jù)。

          2.       包含關(guān)系的類之間不存在繼承關(guān)系。如:主機,外設(shè) ,電腦。 把主機類和外設(shè)類作為電腦類的成員就可以了。

          3.       如果在邏輯上類B是類A的一種,并且類的所有屬性和行為對類而言都有意義,則允許B繼承A的行為和屬性(私有屬性與行為除外)。





               
          posted @ 2009-07-26 17:33 胡鵬 閱讀(218) | 評論 (0)編輯 收藏
                 原帖javaeye上的:  http://yongtech.javaeye.com/blog/428671 ,覺得寫得挺不錯的!不知道您到什么階段了。。。。hoho

          本來我想把這篇文章的名字命名為: <怎樣成為一個優(yōu)秀的Java程序員>的, 但是自己還不夠優(yōu)秀, 而本篇所涉及的都是自己學(xué)習(xí)和工作中的一些經(jīng)驗, 后來一想, 叫<怎樣進階Java>可能更為合適吧. 能給初學(xué)Java的人一個參考, 也就是我本來的心愿. 如果有大牛看到不妥之處, 敬請指正. 我一定會修正的 :).

           

          Java目前是最流行的語言之一,  是很多公司和程序員喜愛的一門程序語言. 而且, Java的入門比C++相對來說要簡單一些, 所以有很大一部分程序員都選擇Java作為自己的開發(fā)語言. 我也是其中之一, 就是因為覺得學(xué)C++太難, 當(dāng)初在學(xué)校學(xué)了將近一個學(xué)期的C++, 啥進步都沒有, 哈哈, 天資太差, 所以才選擇自學(xué)Java(當(dāng)時學(xué)校并沒有開設(shè)Java的課程), 才走上了程序開發(fā)這條路.

           

          Java雖然入門要容易, 然而要精通它, 要成為專家卻很難. 主要原因是Java所涉及的技術(shù)面比較寬, 人的精力總是有限的. 有些Java方面的技術(shù)是必須要要掌握的, 鉆研得越深入越好, 比如多線程技術(shù).

           

          1. 基礎(chǔ)階段

          基礎(chǔ)階段, 可能需要經(jīng)歷1-2年吧. 這個時段, 應(yīng)該多寫一些基礎(chǔ)的小程序(自己動手寫的越多越好). 計算機是一門實踐性很強的學(xué)科, 自己動手的東西, 記憶非常深刻, 效果要勝過讀好多書. 當(dāng)然, 學(xué)Java基礎(chǔ)的時候, 書籍的選擇也非常重要, 好的書籍事半功倍, 能讓你打個非常好的基礎(chǔ). 而差的書籍, 很容易將你帶入歧途, 多走很多彎路. 書籍不在多, 而在乎讀得精(有些書, 你讀十遍都不為過). 我記得我學(xué)Java的第一本書是<Thinking in Java>的中文版, 網(wǎng)上有很多人都建議不要把這本書作為第一本的入門教程來看, 太難. 我卻想在此極力推薦它, 這本書確實是本經(jīng)典之作. 而且書中確實講的也是Java中的一些基礎(chǔ)技術(shù), 沒有什么太難的東西, 只不過比較厚, 學(xué)習(xí)周期比較長, 所以很多人中途會選擇放棄. 其實, 這本書是一本難得的入門教程, 對Java一些基礎(chǔ)的東西, 講得很全, 而且也很清晰, 更重要的是, 這本書能讓你養(yǎng)成很多好的編程習(xí)慣, 例子也很多. 建議你把大部分的例子自己去實現(xiàn)一遍.  我的親身經(jīng)歷, 我記得當(dāng)時認(rèn)真的看了2遍, 花了大概7個月的時間, 不過真的有很好的效果. 另外一個教程, 就是<Java核心技術(shù)>卷一, 卷二的話可以不必要買. 卷一看完, 自己再鉆研一下, 就已經(jīng)能達到卷二的高度了:). 到那時, 你就會覺得看卷二沒啥意思, 感覺浪費錢了. 還有一個, 就是張孝祥的Java視頻, 看視頻有個好處, 就是比看書的記憶要深刻, 還有很多你可以跟著視頻的演示同步操作. 張孝祥的Java視頻對初學(xué)者來說, 確實很有作用. 總結(jié)起來: 看這些資料的時候, 一定要多寫例子, 寫的越多越好!

           

          2. 中級階段

          中級階段, 是一個更漫長的時期, 能否突破此階段, 跟個人的努力和天資有著很大的關(guān)系. 你不得不承認(rèn), 同樣一門新技術(shù), 有些人一個月領(lǐng)悟到的東西, 比你一年的都多. 這就是天資, 程序員是一個需要天才的工作. 我想, 很多人聽說李一男吧, 此君就是這樣的人物, 三個月的時間就能解決好大一幫人幾年解決不了的問題, 給華為某部門帶來了很多的收益. 哦, 這是題外話了, 與此篇的主題無關(guān), 只是本人偶爾的感慨而已:).  這個階段, 就需要研究很多專題性的東西了, 比如: IO的實現(xiàn)原理, 多線程和Java的線程模型, 網(wǎng)絡(luò)編程, swing, RMI, reflect, EJB, JDBC等等很多很多的專題技術(shù), 鉆研得越深越好. 為了更好的提高, 研究的更深入, 你需要經(jīng)常到網(wǎng)絡(luò)上搜索資料, 這個時候往往一本書起不來很大的作用. 選一個JDK版本吧, 目前建議選用1.6, 多多研究它, 尤其是源代碼(盡量! 就是盡自己最大的努力, 雖然研究透是不可能滴). 比如說: util, collection, io, nio, concurrent等等包. 可能有人會反對我說, 不是有API文檔嗎, 為什么還要研究這么多的源代碼? 錯了, 有API文檔, 你僅僅只是知道怎么用而已, 而認(rèn)真仔細(xì)的研讀這些大牛的源碼, 你就會深入更高的一個階層, 自己的編碼, 設(shè)計都會有很大的提高. 如果有能力和精力, 我建議你把JDK的每一行代碼都熟悉一遍, 絕對只有好處, 沒有壞處! 而且你會有些意外的收獲, 比如, 當(dāng)你仔細(xì)地讀完concurrent包的時候(不多, 好像總共是86個類吧), 你就會對Doug Lea佩服得五體投地. 這個時候最忌碰到難題就去尋找?guī)椭? 去網(wǎng)上找答案! 先把自己的腦袋想破吧, 或者等你的老板拿著砍刀沖過來要把你殺了, 再去尋求幫助吧. 對于專題的學(xué)習(xí), 英文原版的閱讀是非常必要的, 看的越多越好, 多上上IBM的developer, SUN的網(wǎng)站吧, 當(dāng)然Javaeye也很不錯:), 有很多大牛, 呵呵.

          這個時候, 你應(yīng)該建立自己的代碼庫了, 你應(yīng)該自己去研究很多有意思的東西了. 從一個200多M的文件中尋找一個字段, 最壞情況(在文件的末尾咯)也只需要1秒左右的時間, 你知道嗎?  這個階段, 有很多很多類似的有趣的東西可以供你去研究, 你需要更多地關(guān)注性能, 規(guī)范性, 多解決一些疑難問題. 需要學(xué)會所有的調(diào)試技術(shù), 運用各種性能工具, 還有JDK附帶的很多工具, 這些你都要熟練得跟屠夫操刀一樣. 也可以看看<Effective Java>, 這本書總結(jié)的也不錯, 對寫高效穩(wěn)定的Java程序有些幫助. 也可以看看模式方面的東西, 但是我建議模式不要濫用, 非得要用的時候才用, 模式往往會把問題搞復(fù)雜:). 總結(jié)起來: 這個階段是一個由點延伸到面的過程, 經(jīng)過不斷的學(xué)習(xí), 演變成全面的深入! Java技術(shù)中你沒什么盲點了, 還能解決很多性能問題和疑難問題, 你就成了一個合格的程序員了! :)  [要想成為優(yōu)秀程序員, 還得對數(shù)據(jù)庫和操作系統(tǒng)很精通.]

           

          3. 高級階段

          高級階段, 我就不敢妄言了. 呵呵, 我感覺自己也是處于中級階段吧. 也是根據(jù)自己的一些經(jīng)驗, 談?wù)勛约旱睦斫獍?

          這個階段, 需要研究各種框架, Spring, struts, Junit, Hibernate, iBatis, Jboss, Tomcat, snmp4j等等, 我覺得這個時候, 只要是用Java實現(xiàn)的經(jīng)典框架, 你都可以去研究. ------在此申明一下, 我的意思不是說會用. 光會用其實是遠(yuǎn)遠(yuǎn)不夠的, 你可以選擇自己喜歡鉆研的框架, 去好好研究一下, 興趣是最好的老師嘛.(2009.07.21)

          建議開始的時候, 研究Junit和Struts吧, 小一點, 里面都采用了很多的模式, 呵呵, 可以熟悉一下, 盡量想想人家為什么這么做. 我建議主要的精力可以花在spring和jboss上, 尤其是jboss,  經(jīng)典中的經(jīng)典, 設(shè)計, 性能, 多線程, 資源管理等等, 你從中可以學(xué)到的東西簡直是太多了. 而且它還有一本寫得很好的參考書, 叫<Jboss管理與開發(fā)核心技術(shù)>, 英文方面的資料也是非常的多. 在工作中如果有機會參與架構(gòu)的設(shè)計, 業(yè)務(wù)問題的討論, 一定想方設(shè)法殺進去! 這對自己的設(shè)計能力, 以及對設(shè)計如何運用在業(yè)務(wù)上有很大的幫助. 畢竟, 程序都是為了更好地實現(xiàn)用戶的業(yè)務(wù)的. 這個時候, 需要更多看看軟件工程和UML方面的資料, 或者自己主持一個項目玩玩, 不一定非得出去拉項目賺錢(能賺錢當(dāng)然更好), 不管成功或失敗, 都是很寶貴的經(jīng)驗, 都能提高很多!  

          posted @ 2009-07-23 19:36 胡鵬 閱讀(229) | 評論 (0)編輯 收藏
                     該書介紹了在Java編程中極具實用價值的經(jīng)驗規(guī)則,這些經(jīng)驗規(guī)則涵蓋了大多數(shù)開發(fā)人員每天所面臨的問題的解決方案。通過對Java平臺設(shè)計專家所使用的技術(shù)的全面描述,揭示了應(yīng)該做什么,不應(yīng)該做什么才能產(chǎn)生清晰、健壯和高效的代碼。
                    每天下班花點時間學(xué)習(xí)下吧,盡量在一個星期內(nèi)把它看完,總結(jié)出來,大多數(shù)內(nèi)容都來自書上,個人覺得該書不錯的地方摘出來。

           第一條:考慮用靜態(tài)工廠方法代替構(gòu)造函數(shù)
              靜態(tài)工廠方法(優(yōu)點):
                   1.每次調(diào)用的時候,不一定要創(chuàng)建一個新的對象,這個可以自由控制。
                   2.它可以返回一個原返回類型的子類型的對象。

           
          第二條:使用私有構(gòu)造函數(shù)強化singleton屬性
          第一種:提供共有的靜態(tài)final域

          public class Elvis{
           
          public static final Elvis INSTANCE = new Elvis();
           
          private Elvis(){
              
           }

           
          }

           

          第二種:提供一個共有的靜態(tài)工廠方法

           1public class Elvis{
           2 private static final Elvis INSTANCE = new Elvis();
           3 private Elvis(){
           4    
           5 }

           6 
           7 public static Elvis getInstance(){
           8  return INSTANCE;
           9 }

          10 
          11}

           

          第一種性能上會稍微好些
          第二種提供了靈活性,在不改變API的前提下,允許我們改變想法,把該類做成singleton,或者不做,容易被修改。

          注意點:為了使一個singleton類變成克序列花的(Serializable),僅僅在聲明中加上implements Serializable是不夠的,
          為了維護singleton性,必須也要提供一個
          private Object readResolve() throws ObjectStreamException{
           return INSTANCE;
          }


          第三條:通過私有構(gòu)造函數(shù)強化不可實例化的能力
          只要讓這個類包含單個顯式的私有構(gòu)造函數(shù),則它就不可被實例化;

          1 public class UtilityClass{
          2  private UtilityClass(){
          3   
          4  }
          5  
          6 }

           

          企圖通過將一個類做成抽象類來強制該類不可被實例化,這是行不通的。該類可以被子類化,并且該子類也可以被實例化。
          更進一步,這樣做會誤導(dǎo)用戶,以為這種類是專門為了繼承而設(shè)計的。

           

          第四條:避免創(chuàng)建重復(fù)的對象
          String s  = new Sting("silly");//這么惡心的代碼就不要寫啦。。。

          1.靜態(tài)工廠方法可幾乎總是優(yōu)先于構(gòu)造方法;Boolean.valueOf(...) > Boolean(...),構(gòu)造函數(shù)每次被調(diào)用的時候都會創(chuàng)建一個新的對象,
          而靜態(tài)工廠方法從來不要求這樣做。

          2.

          public class Person {
              
          private final Date birthDate;
              
              
          public Person(Date date){
                  
          this.birthDate = date;
              }

              
              
          //don't do this
              public boolean isBabyBoomer(){
                  Calendar gmtCal 
          = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
                  gmtCal.set(
          1946,Calendar.JANUARY,1,0,0,0);
                  Date boomStart 
          = gmtCal.getTime();
                  gmtCal.set(
          1965,Calendar.JANUARY,1,0,0,0);
                  Date boomEnd 
          = gmtCal.getTime();
                  
          return birthDate.compareTo(boomStart) >=0 && birthDate.compareTo(boomEnd) <0;
              }

          }

           

           

          isBabyBoomer每次被調(diào)用的時候,都會創(chuàng)建一個新的Calendar,一個新的TimeZone和兩個新的Date實例。。。

          下面的版本避免了這種低效率的動作,代之以一個static 塊初始化Calendar對象,而且最體現(xiàn)效率的是,他的生命周期只實例化一次Calendar并且把
          80年,90年的出生的值賦值給類靜態(tài)變量BOOM_START和BOOM_END

          class Person {
           
          private final Date birthDate;

           
          public Person(Date birthDate) {
            
          this.birthDate = birthDate;
           }


           
           
          private static final Date BOOM_START;
           
          private static final Date BOOM_END;
           
          static {
            Calendar gmtCal 
          = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
            gmtCal.set(
          1980, Calendar.JANUARY, 1000);
            BOOM_START 
          = gmtCal.getTime();
            gmtCal.set(
          1990, Calendar.JANUARY, 1000);
            BOOM_END 
          = gmtCal.getTime();
           }


           
          public boolean isBabyBoomer() {
            
          return birthDate.compareTo(BOOM_START) >= 0
              
          && birthDate.compareTo(BOOM_END) < 0;
           }


           

           


           

          posted @ 2009-07-23 19:31 胡鵬 閱讀(201) | 評論 (0)編輯 收藏

            最近在翻《首先,打破一切常規(guī)》,書不只翻一遍了,每次都會有一些新的收獲.書中經(jīng)常提到的6個問題越想越覺得有道理,列出跟大家分享:

          1.你知道對你工作的要求嗎?

          第一優(yōu)先級的問題,如果不知道對你的工作要求,那么你如何衡量你工作的好壞?其他人如何衡量你的工作成果?首當(dāng)其沖需要考慮的問題.

          2.你有做好你當(dāng)前工作的材料和設(shè)備或者資源嗎?

          當(dāng)然明確工作要求的時候需要明確你達到你目標(biāo)的途徑,此時需要衡量你能掌控的資源,或者你能夠使用到的潛在資源.

          3.在工作中你每天都有機會做你最擅長的事情嗎?

          是否能夠發(fā)揮自己的潛力,是否是自己的興趣愛好,是否能做的更好.

          4.過去的7天內(nèi),你有因你的工作出色而受到表揚嗎?

          周圍同事或者你的主管關(guān)注你的個人價值,為什么會受到表揚?是否可以在這件工作上受到一貫的認(rèn)可.

          5.你覺得你的主管或者同事關(guān)心你的個人情況嗎?

          恒定自己在團隊中的作用,如果不關(guān)心,為什么?你是否了解過其他人的感受?如果關(guān)心?關(guān)心那點?如何滿足期望.

          6.工作單位里面有人會鼓勵你的發(fā)展嗎?

          職業(yè)發(fā)展的考慮,企業(yè)是否值得呆下去,是否能夠共同進步.

           

          定期拿這些問題進行自勉,會有很多收獲.包括你的同事,你的主管,你的合作伙伴,甚至?xí)淖兡愕娜松?

          posted @ 2009-06-29 12:22 胡鵬 閱讀(203) | 評論 (0)編輯 收藏

          問題:

          下面一個簡單的類:

          public class MyTest {
           private static String className = String.class.getName(); //紅色部分是下面問題的關(guān)鍵
           public static void main(String[] args){
            System.out.println(className);   
           }
          }

          經(jīng)eclipse3.1.1編譯后(指定類兼容性版本為1.4),再反編譯的結(jié)果是:

          public class MyTest
          {

              public MyTest()
              {
              }

              public static void main(String args[])
              {
                  System.out.println(className);
              }

              private static String className;

              static
              {
                  className = java.lang.String.class.getName();
              }
          }

          而經(jīng)過sun javac(或者ant, antx)編譯后(JDK版本1.4,或者JDK1.5,但是編譯結(jié)果指定版本為1.4),再反編譯的結(jié)果是:

          public class MyTest
          {

              public MyTest()
              {
              }

              public static void main(String args[])
              {
                  System.out.println(className);
              }

              static Class _mthclass$(String x0)
              {
                  return Class.forName(x0);
                  ClassNotFoundException x1;
                  x1;
                  throw (new NoClassDefFoundError()).initCause(x1);
              }

              private static String className;

              static
              {
                  className = (java.lang.String.class).getName();
              }
          }

           

          也就是說sun javac編譯出來的結(jié)果里面多了一個_mthclass$方法,這個通常不會有什么問題,不過在使用hot swap技術(shù)(例如Antx eclipse plugin中的快速部署插件利用hot swap來實現(xiàn)類的熱替換,或者某些類序列化的地方,這個就成為問題了。

           

          用_mthclass$在google上搜一把,結(jié)果不多,比較有價值的是這一篇:http://coding.derkeiler.com/Archive/Java/comp.lang.java.softwaretools/2004-01/0138.html

          按照這個說法,這個問題是由于Sun本身沒有遵循規(guī)范,而eclipse compiler遵循規(guī)范導(dǎo)致的,而且eclipse compiler是沒有辦法替換的。

           

          嘗試將JDK版本換成1.5,sun javac生成出來的_mthclass$是不見了,不過,這回奇怪的是eclipse的編譯結(jié)果中多了一個成員變量class$0,
          下面是經(jīng)eclipse3.1.1編譯后(指定類兼容性版本為5.0),再反編譯的結(jié)果:
          public class MyTest
          {

              public MyTest()
              {
              }

              public static void main(String args[])
              {
                  System.out.println(className);
              }

              private static String className = java/lang/String.getName();
              static Class class$0;

          }
          而經(jīng)過sun javac(或者ant, antx)編譯后(JDK版本1.5),再反編譯的結(jié)果是:
          public class MyTest
          {

              public MyTest()
              {
              }

              public static void main(String args[])
              {
                  System.out.println(className);
              }

              private static String className = java/lang/String.getName();

          }

          再在goole上搜了一把,發(fā)現(xiàn)了Eclipse3.2有兩個比較重要的特征:
          1.與javac的兼容性更好。
          2.提供了單獨的編譯器,可以在eclipse外部使用,包括ant中使用。

          于是下載eclipse3.2版本,首先驗證一下其與sun javac的兼容性如何,
          使用JDK1.4版本的時候,還是老樣子,sun javac編譯出來的_mthclass$方法在eclipse3.2的編譯結(jié)果中還是不存在,所以還是不兼容的。
          不過使用JDK1.5版本的時候,這會eclipse 3.2的編譯結(jié)果總算和sun javac一致了。

          雖然,用JDK1.5加上eclipse 3.2已經(jīng)保證了這個類在兩種編譯器下的兼容性,不過總覺得不踏實:
          1.誰知道這兩個編譯器還有沒有其它不兼容的地方呢?
          2.版本要求太嚴(yán)格,很多由于各種原因沒有使用這些版本的很麻煩。

          因此,還是從根本上解決這個問題比較合適:根本上解決最好就是不要使用兩種不同的編譯器,而使用同一種。
          由于eclipse環(huán)境下的編譯器是不可替換的,所以企圖都使用sun javac的方式不太可行,那么統(tǒng)一使用eclipse自帶的編譯器如何呢?
          剛才提到的eclipse3.2的第二個比較重要的特性就派上用場了。
          獨立的eclipse編譯器(1M大小而已)可以在如下地址下載:http://www.eclipse.org/downloads/download.php?file=/eclipse/downloads/drops/R-3.2-200606291905/ecj.jar
          這個獨立的編譯器在antx下的使用也很簡單:(關(guān)于該編譯器的獨立使用或者ant下面的使用可以參看this help section: JDT Plug-in Developer Guide>Programmer's Guide>JDT Core>Compiling Java code)
          1.將下載下來的編譯器放在ANTX_HOME/lib目錄下面。
          2.在總控項目文件的project.xml增加這么一行即可:<property name="build.compiler" value="org.eclipse.jdt.core.JDTCompilerAdapter"/>
          這樣就保證了通過antx打包的類也是用eclipse的編譯器編譯出來的,當(dāng)然就不應(yīng)該存在類不兼容的情況了。

           

          實際上,eclipse3.1.1版本也已經(jīng)提供了獨立的eclipse編譯器,不過當(dāng)時并沒有單獨提供獨立的包下載,如果希望使用3.1.1版本的eclipse編譯器,可以使用org.eclipse.jdt.core_3.1.1.jar以及其中包含的jdtCompilerAdapter.jar。(eclipse3.1.1環(huán)境的編譯器我沒有獨立驗證過)

           


          posted @ 2009-05-23 02:15 胡鵬 閱讀(4786) | 評論 (0)編輯 收藏

          Unicode是一種字符編碼規(guī)范 。

          先從ASCII說起。ASCII是用來表示英文字符的一種編碼規(guī)范,每個ASCII字符占用1個字節(jié)(8bits) 

          因此,ASCII編碼可以表示的最大字符數(shù)是256,其實英文字符并沒有那么多,一般只用前128個(最高位為0),其中包括了控制字符、數(shù)字、大小寫字母和其他一些符號 。

          而最高位為1的另128個字符被成為“擴展ASCII”,一般用來存放英文的制表符、部分音標(biāo)字符等等的一些其他符號 

          這種字符編碼規(guī)范顯然用來處理英文沒有什么問題 。(實際上也可以用來處理法文、德文等一些其他的西歐字符,但是不能和英文通用),但是面對中文、阿拉伯文之類復(fù)雜的文字,255個字符顯然不夠用 

          于是,各個國家紛紛制定了自己的文字編碼規(guī)范,其中中文的文字編碼規(guī)范叫做“GB2312-80”,它是和ASCII兼容的一種編碼規(guī)范,其實就是利用擴展ASCII沒有真正標(biāo)準(zhǔn)化這一點,把一個中文字符用兩個擴展ASCII字符來表示。 

          但是這個方法有問題,最大的問題就是,中文文字沒有真正屬于自己的編碼,因為擴展ASCII碼雖然沒有真正的標(biāo)準(zhǔn)化,但是PC里的ASCII碼還是有一個事實標(biāo)準(zhǔn)的(存放著英文制表符),所以很多軟件利用這些符號來畫表格。這樣的軟件用到中文系統(tǒng)中,這些表格符就會被誤認(rèn)作中文字,破壞版面。而且,統(tǒng)計中英文混合字符串中的字?jǐn)?shù),也是比較復(fù)雜的,我們必須判斷一個ASCII碼是否擴展,以及它的下一個ASCII是否擴展,然后才“猜”那可能是一個中文字 。

          總之當(dāng)時處理中文是很痛苦的。而更痛苦的是GB2312是國家標(biāo)準(zhǔn),臺灣當(dāng)時有一個Big5編碼標(biāo)準(zhǔn),很多編碼和GB是相同的,所以……,嘿嘿。 

          這時候,我們就知道,要真正解決中文問題,不能從擴展ASCII的角度入手,也不能僅靠中國一家來解決。而必須有一個全新的編碼系統(tǒng),這個系統(tǒng)要可以將中文、英文、法文、德文……等等所有的文字統(tǒng)一起來考慮,為每個文字都分配一個單獨的編碼,這樣才不會有上面那種現(xiàn)象出現(xiàn)。 

          于是,Unicode誕生了。 

          Unicode有兩套標(biāo)準(zhǔn),一套叫UCS-2(Unicode-16),用2個字節(jié)為字符編碼,另一套叫UCS-4(Unicode-32),用4個字節(jié)為字符編碼。 

          以目前常用的UCS-2為例,它可以表示的字符數(shù)為2^16=65535,基本上可以容納所有的歐美字符和絕大部分的亞洲字符 。

          UTF-8的問題后面會提到 。

          在Unicode里,所有的字符被一視同仁。漢字不再使用“兩個擴展ASCII”,而是使用“1個Unicode”,注意,現(xiàn)在的漢字是“一個字符”了,于是,拆字、統(tǒng)計字?jǐn)?shù)這些問題也就自然而然的解決了 。

          但是,這個世界不是理想的,不可能在一夜之間所有的系統(tǒng)都使用Unicode來處理字符,所以Unicode在誕生之日,就必須考慮一個嚴(yán)峻的問題:和ASCII字符集之間的不兼容問題。 

          我們知道,ASCII字符是單個字節(jié)的,比如“A”的ASCII是65。而Unicode是雙字節(jié)的,比如“A”的Unicode是0065,這就造成了一個非常大的問題:以前處理ASCII的那套機制不能被用來處理Unicode了 。

          另一個更加嚴(yán)重的問題是,C語言使用'\0'作為字符串結(jié)尾,而Unicode里恰恰有很多字符都有一個字節(jié)為0,這樣一來,C語言的字符串函數(shù)將無法正常處理Unicode,除非把世界上所有用C寫的程序以及他們所用的函數(shù)庫全部換掉 。

          于是,比Unicode更偉大的東東誕生了,之所以說它更偉大是因為它讓Unicode不再存在于紙上,而是真實的存在于我們大家的電腦中。那就是:UTF 。

          UTF= UCS Transformation Format UCS轉(zhuǎn)換格式 

          它是將Unicode編碼規(guī)則和計算機的實際編碼對應(yīng)起來的一個規(guī)則。現(xiàn)在流行的UTF有2種:UTF-8和UTF-16 。

          其中UTF-16和上面提到的Unicode本身的編碼規(guī)范是一致的,這里不多說了。而UTF-8不同,它定義了一種“區(qū)間規(guī)則”,這種規(guī)則可以和ASCII編碼保持最大程度的兼容 。

          UTF-8有點類似于Haffman編碼,它將Unicode編碼為00000000-0000007F的字符,用單個字節(jié)來表示; 

          00000080-000007FF的字符用兩個字節(jié)表示 

          00000800-0000FFFF的字符用3字節(jié)表示 

          因為目前為止Unicode-16規(guī)范沒有指定FFFF以上的字符,所以UTF-8最多是使用3個字節(jié)來表示一個字符。但理論上來說,UTF-8最多需要用6字節(jié)表示一個字符。 

          在UTF-8里,英文字符仍然跟ASCII編碼一樣,因此原先的函數(shù)庫可以繼續(xù)使用。而中文的編碼范圍是在0080-07FF之間,因此是2個字節(jié)表示(但這兩個字節(jié)和GB編碼的兩個字節(jié)是不同的),用專門的Unicode處理類可以對UTF編碼進行處理。 

          下面說說中文的問題。 

          由于歷史的原因,在Unicode之前,一共存在過3套中文編碼標(biāo)準(zhǔn)。 

          GB2312-80,是中國大陸使用的國家標(biāo)準(zhǔn),其中一共編碼了6763個常用簡體漢字。Big5,是臺灣使用的編碼標(biāo)準(zhǔn),編碼了臺灣使用的繁體漢字,大概有8千多個。HKSCS,是中國香港使用的編碼標(biāo)準(zhǔn),字體也是繁體,但跟Big5有所不同。 

          這3套編碼標(biāo)準(zhǔn)都采用了兩個擴展ASCII的方法,因此,幾套編碼互不兼容,而且編碼區(qū)間也各有不同 

          因為其不兼容性,在同一個系統(tǒng)中同時顯示GB和Big5基本上是不可能的。當(dāng)時的南極星、RichWin等等軟件,在自動識別中文編碼、自動顯示正確編碼方面都做了很多努力 。

          他們用了怎樣的技術(shù)我就不得而知了,我知道好像南極星曾經(jīng)以同屏顯示繁簡中文為賣點。 

          后來,由于各方面的原因,國際上又制定了針對中文的統(tǒng)一字符集GBK和GB18030,其中GBK已經(jīng)在Windows、Linux等多種操作系統(tǒng)中被實現(xiàn)。 

          GBK兼容GB2312,并增加了大量不常用漢字,還加入了幾乎所有的Big5中的繁體漢字。但是GBK中的繁體漢字和Big5中的幾乎不兼容。 

          GB18030相當(dāng)于是GBK的超集,比GBK包含的字符更多。據(jù)我所知目前還沒有操作系統(tǒng)直接支持GB18030。 


          談?wù)刄nicode編碼,簡要解釋UCS、UTF、BMP、BOM等名詞 
          這是一篇程序員寫給程序員的趣味讀物。所謂趣味是指可以比較輕松地了解一些原來不清楚的概念,增進知識,類似于打RPG游戲的升級。整理這篇文章的動機是兩個問題:

          問題一: 
          使用Windows記事本的“另存為”,可以在GBK、Unicode、Unicode big endian和UTF-8這幾種編碼方式間相互轉(zhuǎn)換。同樣是txt文件,Windows是怎樣識別編碼方式的呢?

          我很早前就發(fā)現(xiàn)Unicode、Unicode big endian和UTF-8編碼的txt文件的開頭會多出幾個字節(jié),分別是FF、FE(Unicode),FE、FF(Unicode big endian),EF、BB、BF(UTF-8)。但這些標(biāo)記是基于什么標(biāo)準(zhǔn)呢?

          問題二: 
          最近在網(wǎng)上看到一個ConvertUTF.c,實現(xiàn)了UTF-32、UTF-16和UTF-8這三種編碼方式的相互轉(zhuǎn)換。對于Unicode(UCS2)、GBK、UTF-8這些編碼方式,我原來就了解。但這個程序讓我有些糊涂,想不起來UTF-16和UCS2有什么關(guān)系。 
          查了查相關(guān)資料,總算將這些問題弄清楚了,順帶也了解了一些Unicode的細(xì)節(jié)。寫成一篇文章,送給有過類似疑問的朋友。本文在寫作時盡量做到通俗易懂,但要求讀者知道什么是字節(jié),什么是十六進制。

          0、big endian和little endian
          big endian和little endian是CPU處理多字節(jié)數(shù)的不同方式。例如“漢”字的Unicode編碼是6C49。那么寫到文件里時,究竟是將6C寫在前面,還是將49寫在前面?如果將6C寫在前面,就是big endian。還是將49寫在前面,就是little endian。

          “endian”這個詞出自《格列佛游記》。小人國的內(nèi)戰(zhàn)就源于吃雞蛋時是究竟從大頭(Big-Endian)敲開還是從小頭(Little-Endian)敲開,由此曾發(fā)生過六次叛亂,其中一個皇帝送了命,另一個丟了王位。

          我們一般將endian翻譯成“字節(jié)序”,將big endian和little endian稱作“大尾”和“小尾”。

          1、字符編碼、內(nèi)碼,順帶介紹漢字編碼
          字符必須編碼后才能被計算機處理。計算機使用的缺省編碼方式就是計算機的內(nèi)碼。早期的計算機使用7位的ASCII編碼,為了處理漢字,程序員設(shè)計了用于簡體中文的GB2312和用于繁體中文的big5。

          GB2312(1980年)一共收錄了7445個字符,包括6763個漢字和682個其它符號。漢字區(qū)的內(nèi)碼范圍高字節(jié)從B0-F7,低字節(jié)從A1-FE,占用的碼位是72*94=6768。其中有5個空位是D7FA-D7FE。

          GB2312支持的漢字太少。1995年的漢字?jǐn)U展規(guī)范GBK1.0收錄了21886個符號,它分為漢字區(qū)和圖形符號區(qū)。漢字區(qū)包括21003個字符。2000年的GB18030是取代GBK1.0的正式國家標(biāo)準(zhǔn)。該標(biāo)準(zhǔn)收錄了27484個漢字,同時還收錄了藏文、蒙文、維吾爾文等主要的少數(shù)民族文字。現(xiàn)在的PC平臺必須支持GB18030,對嵌入式產(chǎn)品暫不作要求。所以手機、MP3一般只支持GB2312。

          從ASCII、GB2312、GBK到GB18030,這些編碼方法是向下兼容的,即同一個字符在這些方案中總是有相同的編碼,后面的標(biāo)準(zhǔn)支持更多的字符。在這些編碼中,英文和中文可以統(tǒng)一地處理。區(qū)分中文編碼的方法是高字節(jié)的最高位不為0。按照程序員的稱呼,GB2312、GBK到GB18030都屬于雙字節(jié)字符集 (DBCS)。

          有的中文Windows的缺省內(nèi)碼還是GBK,可以通過GB18030升級包升級到GB18030。不過GB18030相對GBK增加的字符,普通人是很難用到的,通常我們還是用GBK指代中文Windows內(nèi)碼。

          這里還有一些細(xì)節(jié):

          GB2312的原文還是區(qū)位碼,從區(qū)位碼到內(nèi)碼,需要在高字節(jié)和低字節(jié)上分別加上A0。

          在DBCS中,GB內(nèi)碼的存儲格式始終是big endian,即高位在前。

          GB2312的兩個字節(jié)的最高位都是1。但符合這個條件的碼位只有128*128=16384個。所以GBK和GB18030的低字節(jié)最高位都可能不是1。不過這不影響DBCS字符流的解析:在讀取DBCS字符流時,只要遇到高位為1的字節(jié),就可以將下兩個字節(jié)作為一個雙字節(jié)編碼,而不用管低字節(jié)的高位是什么。

          2、Unicode、UCS和UTF
          前面提到從ASCII、GB2312、GBK到GB18030的編碼方法是向下兼容的。而Unicode只與ASCII兼容(更準(zhǔn)確地說,是與ISO-8859-1兼容),與GB碼不兼容。例如“漢”字的Unicode編碼是6C49,而GB碼是BABA。

          Unicode也是一種字符編碼方法,不過它是由國際組織設(shè)計,可以容納全世界所有語言文字的編碼方案。Unicode的學(xué)名是"Universal Multiple-Octet Coded Character Set",簡稱為UCS。UCS可以看作是"Unicode Character Set"的縮寫。

          根據(jù)維基百科全書(http://zh.wikipedia.org/wiki/)的記載:歷史上存在兩個試圖獨立設(shè)計Unicode的組織,即國際標(biāo)準(zhǔn)化組織(ISO)和一個軟件制造商的協(xié)會(unicode.org)。ISO開發(fā)了ISO 10646項目,Unicode協(xié)會開發(fā)了Unicode項目。

          在1991年前后,雙方都認(rèn)識到世界不需要兩個不兼容的字符集。于是它們開始合并雙方的工作成果,并為創(chuàng)立一個單一編碼表而協(xié)同工作。從Unicode2.0開始,Unicode項目采用了與ISO 10646-1相同的字庫和字碼。

          目前兩個項目仍都存在,并獨立地公布各自的標(biāo)準(zhǔn)。Unicode協(xié)會現(xiàn)在的最新版本是2005年的Unicode 4.1.0。ISO的最新標(biāo)準(zhǔn)是10646-3:2003。

          UCS規(guī)定了怎么用多個字節(jié)表示各種文字。怎樣傳輸這些編碼,是由UTF(UCS Transformation Format)規(guī)范規(guī)定的,常見的UTF規(guī)范包括UTF-8、UTF-7、UTF-16。

          IETF的RFC2781和RFC3629以RFC的一貫風(fēng)格,清晰、明快又不失嚴(yán)謹(jǐn)?shù)孛枋隽薝TF-16和UTF-8的編碼方法。我總是記不得IETF是Internet Engineering Task Force的縮寫。但IETF負(fù)責(zé)維護的RFC是Internet上一切規(guī)范的基礎(chǔ)。

          3、UCS-2、UCS-4、BMP

          UCS有兩種格式:UCS-2和UCS-4。顧名思義,UCS-2就是用兩個字節(jié)編碼,UCS-4就是用4個字節(jié)(實際上只用了31位,最高位必須為0)編碼。下面讓我們做一些簡單的數(shù)學(xué)游戲:

          UCS-2有2^16=65536個碼位,UCS-4有2^31=2147483648個碼位。

          UCS-4根據(jù)最高位為0的最高字節(jié)分成2^7=128個group。每個group再根據(jù)次高字節(jié)分為256個plane。每個plane根據(jù)第3個字節(jié)分為256行 (rows),每行包含256個cells。當(dāng)然同一行的cells只是最后一個字節(jié)不同,其余都相同。

          group 0的plane 0被稱作Basic Multilingual Plane, 即BMP。或者說UCS-4中,高兩個字節(jié)為0的碼位被稱作BMP。

          將UCS-4的BMP去掉前面的兩個零字節(jié)就得到了UCS-2。在UCS-2的兩個字節(jié)前加上兩個零字節(jié),就得到了UCS-4的BMP。而目前的UCS-4規(guī)范中還沒有任何字符被分配在BMP之外。

          4、UTF編碼

          UTF-8就是以8位為單元對UCS進行編碼。從UCS-2到UTF-8的編碼方式如下:

          UCS-2編碼(16進制) UTF-8 字節(jié)流(二進制) 
          0000 - 007F 0xxxxxxx 
          0080 - 07FF 110xxxxx 10xxxxxx 
          0800 - FFFF 1110xxxx 10xxxxxx 10xxxxxx 

          例如“漢”字的Unicode編碼是6C49。6C49在0800-FFFF之間,所以肯定要用3字節(jié)模板了:1110xxxx 10xxxxxx 10xxxxxx。將6C49寫成二進制是:0110 110001 001001, 用這個比特流依次代替模板中的x,得到:11100110 10110001 10001001,即E6 B1 89。

          讀者可以用記事本測試一下我們的編碼是否正確。

          UTF-16以16位為單元對UCS進行編碼。對于小于0x10000的UCS碼,UTF-16編碼就等于UCS碼對應(yīng)的16位無符號整數(shù)。對于不小于0x10000的UCS碼,定義了一個算法。不過由于實際使用的UCS2,或者UCS4的BMP必然小于0x10000,所以就目前而言,可以認(rèn)為UTF-16和UCS-2基本相同。但UCS-2只是一個編碼方案,UTF-16卻要用于實際的傳輸,所以就不得不考慮字節(jié)序的問題。

          5、UTF的字節(jié)序和BOM
          UTF-8以字節(jié)為編碼單元,沒有字節(jié)序的問題。UTF-16以兩個字節(jié)為編碼單元,在解釋一個UTF-16文本前,首先要弄清楚每個編碼單元的字節(jié)序。例如收到一個“奎”的Unicode編碼是594E,“乙”的Unicode編碼是4E59。如果我們收到UTF-16字節(jié)流“594E”,那么這是“奎”還是“乙”?

          Unicode規(guī)范中推薦的標(biāo)記字節(jié)順序的方法是BOM。BOM不是“Bill Of Material”的BOM表,而是Byte Order Mark。BOM是一個有點小聰明的想法:

          在UCS編碼中有一個叫做"ZERO WIDTH NO-BREAK SPACE"的字符,它的編碼是FEFF。而FFFE在UCS中是不存在的字符,所以不應(yīng)該出現(xiàn)在實際傳輸中。UCS規(guī)范建議我們在傳輸字節(jié)流前,先傳輸字符"ZERO WIDTH NO-BREAK SPACE"。

          這樣如果接收者收到FEFF,就表明這個字節(jié)流是Big-Endian的;如果收到FFFE,就表明這個字節(jié)流是Little-Endian的。因此字符"ZERO WIDTH NO-BREAK SPACE"又被稱作BOM。

          UTF-8不需要BOM來表明字節(jié)順序,但可以用BOM來表明編碼方式。字符"ZERO WIDTH NO-BREAK SPACE"的UTF-8編碼是EF BB BF(讀者可以用我們前面介紹的編碼方法驗證一下)。所以如果接收者收到以EF BB BF開頭的字節(jié)流,就知道這是UTF-8編碼了。

          Windows就是使用BOM來標(biāo)記文本文件的編碼方式的。

          6、進一步的參考資料
          本文主要參考的資料是 "Short overview of ISO-IEC 10646 and Unicode" (http://www.nada.kth.se/i18n/ucs/unicode-iso10646-oview.html)。

          我還找了兩篇看上去不錯的資料,不過因為我開始的疑問都找到了答案,所以就沒有看:

          "Understanding Unicode A general introduction to the Unicode Standard" (http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&item_id=IWS-Chapter04a
          "Character set encoding basics Understanding character set encodings and legacy encodings" (http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&item_id=IWS-Chapter03)


          posted @ 2009-05-16 01:52 胡鵬 閱讀(227) | 評論 (0)編輯 收藏
          下面列舉10個攻擊:

            1.AJAX中的跨站點腳本

            前幾個月,人們發(fā)現(xiàn)了多種跨站點的腳本攻擊。在此類攻擊中,受害者的包含信息的瀏覽器上會運行來自特定網(wǎng)站的惡意JAVA腳本代碼。 Yamanner蠕蟲就是一個最近的范例,它利用Yahoo郵件的AJAX調(diào)用中的跨站點腳本機會來攻擊受害者。另一個近期的范例就是Samy蠕蟲,它利 用MySpace.com的跨站點腳本漏洞來攻擊。AJAX在客戶端上運行,它允許錯誤書寫的腳本被攻擊者利用。攻擊者能夠編寫惡意鏈接來哄騙那些沒有準(zhǔn) 備的用戶,讓他們用瀏覽器去訪問特定的網(wǎng)頁。傳統(tǒng)應(yīng)用中也存在這樣的弱點,但AJAX給它添加了更多可能的漏洞。例子, Yamanner蠕蟲利用了Yahoo Mail的AJAX的跨站腳本漏洞,Samy蠕蟲利用了MySpace.com的跨站腳本漏洞。

            2.XML中毒

            很多Web2.0應(yīng)用中,XML傳輸在服務(wù)器和瀏覽器之間往復(fù)。網(wǎng)絡(luò)應(yīng)用接收來自AJAX客戶端的XML塊。這XML塊很可能染毒。多次將遞歸 負(fù)載應(yīng)用到產(chǎn)出相似的XML節(jié)點,這樣的技術(shù)還并不普遍。如果機器的處理能力較弱,這將導(dǎo)致服務(wù)器拒絕服務(wù)。很多攻擊者還制作結(jié)構(gòu)錯誤的XML文檔,這些 文檔會擾亂服務(wù)器上所使用的依賴剖析機制的邏輯。服務(wù)器端的剖析機制有兩種類型,它們是SAX和DOM。網(wǎng)絡(luò)服務(wù)也使用相同的攻擊向量,這是因為網(wǎng)絡(luò)服務(wù) 接收SOAP消息,而SOAP就是XML消息。在應(yīng)用層大范圍地使用XMLs使攻擊者有更多的機會利用這個新的攻擊向量。

            XML外部實體參照是能被攻擊者偽造的一個XML的屬性。這會使攻擊者能夠利用人意的文件或者TCP連接的缺陷。XML schema中毒是另一個XML中毒的攻擊向量,它能夠改變執(zhí)行的流程。這個漏洞能幫助攻擊者獲得機密信息。攻擊者可以通過復(fù)制節(jié)點進行DOS攻擊,或者生成不合法的XML導(dǎo)致服務(wù)器端邏輯的中斷。攻擊者也可以操縱外部實體,導(dǎo)致打開任何文件或TCP連接端口。XML數(shù)據(jù)定義的中毒也可以導(dǎo)致運行流程的改變,助攻擊者獲取機密信息。

            3.惡意AJAX代碼的執(zhí)行

            AJAX調(diào)用非常不易察覺,終端用戶無法確定瀏覽器是否正在用XMLHTTP請求對象發(fā)出無記載的調(diào)用。瀏覽器發(fā)出AJAX調(diào)用給任意網(wǎng)站的時 候,該網(wǎng)站會對每個請求回應(yīng)以cookies。這將導(dǎo)致出現(xiàn)泄漏的潛在可能性。例如,約翰已經(jīng)登陸了他的銀行,并且通過了服務(wù)器認(rèn)證。完成認(rèn)證過程后,他 會得到一個會話 cookie。銀行的頁面中包含了很多關(guān)鍵信息。現(xiàn)在,他去瀏覽器他網(wǎng)頁,并同時仍然保持銀行賬戶的登陸狀態(tài)。他可能會剛好訪問一個攻擊者的網(wǎng)頁,在這個 網(wǎng)頁上攻擊者寫了不易被察覺的AJAX 代碼,這個代碼不用經(jīng)過約翰的同意,就能夠發(fā)出后臺調(diào)用給約翰的銀行網(wǎng)頁,因而能夠從銀行頁面取得關(guān)鍵信息并且把這些信息發(fā)送到攻擊者的網(wǎng)站。這將導(dǎo)致機 密信息的泄漏甚至引發(fā)安全突破。AJAX 編碼可以在不為用戶所知的情形下運行,假如用戶先登錄一個機密網(wǎng)站,機密網(wǎng)站返回一個會話cookie,然后用戶在沒有退出機密網(wǎng)站的情形下,訪問攻擊者 的網(wǎng)站,攻擊者網(wǎng)頁上的AJAX編碼可以(通過這個會話cookie?)去訪問機密網(wǎng)站上的網(wǎng)頁,從而竊取用戶的機密信息。(注:這里的解釋有點含糊,理 論上講,瀏覽器不會把一個網(wǎng)站的會話cookie傳給另外一個網(wǎng)站的,即文中的這句“When the browser makes an AJAX call to any Web site it replays cookies for each request. ”,不完全對)

            4.RSS/Atom 注入

          這是一項新的web2.0攻擊。RSS反饋是人們在門戶網(wǎng)站或者網(wǎng)絡(luò)應(yīng)用中共享信息的常用手段。網(wǎng)絡(luò)應(yīng)用接受這些反饋然后發(fā)送給客戶端的瀏覽器。人們可 以在該RSS反饋中插入文本的JavaScript來產(chǎn)生對用戶瀏覽器的攻擊。訪問特定網(wǎng)站的終端用戶加載了帶有該RSS反饋的網(wǎng)頁,這個腳本 就會運行起來——它能夠往用戶的電腦中安裝軟件或者竊取cookies信息。這就是一個致命的客戶端攻擊。更糟糕的是,它可以變異。隨著RSS和ATOM 反饋成為網(wǎng)絡(luò)應(yīng)用中整合的組件,在服務(wù)器端將數(shù)據(jù)發(fā)布給終端用戶之前,過濾特定字符是非常必要的。攻擊者可以在RSS feeds里注入Javascript腳本,如果服務(wù)器端沒有過濾掉這些腳本的話,在瀏覽器端會造成問題。

            5.WSDL掃描和enumeration

            WSDL(網(wǎng)絡(luò)服務(wù)界定語言)是網(wǎng)絡(luò)服務(wù)的一個接口。該文件提供了技術(shù),開放方法,創(chuàng)新形式等等的關(guān)鍵信息。這是非常敏感信息,而且能夠幫助人 們決定利用什么弱點來攻擊。如果將不必要的功能或者方法一直開著,這會為網(wǎng)絡(luò)服務(wù)造成潛在的災(zāi)難。保護WSDL文件或者限定對其的訪問是非常重要的。在實 際情況中,很有可能找到一些使用WSDL掃描的一些漏洞。WSDL提供了Web服務(wù)所用的技術(shù),以及外露的方法,調(diào)用的模式等信息。假如Web服務(wù)對不必要的方法沒有禁止的話,攻擊者可以通過WSDL掃描找到潛在的攻擊點。

            6.AJAX常規(guī)程序中客戶端的確認(rèn)

            基于web2.0的應(yīng)用使用AJAX常規(guī)程序來在客戶端上進行很多操作,比如客戶端數(shù)據(jù)類型的確認(rèn),內(nèi)容檢查,數(shù)據(jù)域等等。正常情況下,服務(wù)端 也應(yīng)該備份這些客戶端檢查信息。大部分開發(fā)者都沒有這么做;他們這樣做的理由是,他們假設(shè)這樣的確認(rèn)是由AJAX常規(guī)程序來負(fù)責(zé)的。避開基于AJAX的確 認(rèn)和直接發(fā)送POST或者GET請求給那些應(yīng)用——這些應(yīng)用是諸如SQL注入,LDAP注入等類隨確認(rèn)進入的攻擊主要來源,它們能夠攻擊網(wǎng)絡(luò)應(yīng)用的關(guān)鍵資 源——都是可以做到的。這都增加了能夠為攻擊者所利用的潛在攻擊向量的數(shù)量。假如開發(fā)人員只依賴客戶端驗證,不在服務(wù)器端重新驗證的話,會導(dǎo)致SQL注入,LDAP注入等等。

            7.網(wǎng)絡(luò)服務(wù)路由問題

            網(wǎng)絡(luò)服務(wù)安全協(xié)議包括WS-Routing服務(wù)。WS-Routing允許SOAP消息在互聯(lián)網(wǎng)上各種各樣不同的節(jié)點中的特別序列中傳輸。通常 加密的信息在這些節(jié)點來回傳送。交互的節(jié)點中的任意一個被攻擊都將致使攻擊者能夠訪問到在兩個端點之間傳輸?shù)腟OAP消息。這將造成SOAP消息的嚴(yán)重的 安全泄漏。隨著網(wǎng)絡(luò)應(yīng)用開始被網(wǎng)絡(luò)服務(wù)框架所采用,攻擊者們開始轉(zhuǎn)而利用這些新協(xié)議和新的攻擊向量。Web服務(wù)安全協(xié)議使用WS-Routing服務(wù),假如任何中轉(zhuǎn)站被攻占,SOAP消息可以被截獲。

            8.SOAP消息的參數(shù)操作

            網(wǎng)絡(luò)服務(wù)接收信息和來自SOAP消息的變量。修改這些變量是很可能的。例如,“10”是SOAP消息中多個節(jié)點中的一個。攻擊者可以修改點,并 且嘗試不同種的注入攻擊——比如,SQL,LDAP,XPATH,命令行解釋器——并且探索能被他用來掌握及其內(nèi)部信息的攻擊向量。網(wǎng)絡(luò)服務(wù)代碼中錯誤的 或者不夠完備的輸入確認(rèn)使網(wǎng)絡(luò)服務(wù)應(yīng)用易于發(fā)生泄漏.這是一個目標(biāo)指向網(wǎng)絡(luò)服務(wù)所帶的網(wǎng)絡(luò)應(yīng)用的一項新的攻擊向量。類似于SQL注入,假如對SOAP消息里節(jié)點的數(shù)據(jù)不做驗證的話。

            9.SOAP消息中的XPATH注入

            XPATH是一種用來查詢XML文檔的語言,它跟SQL語句很類似:我們提供某些信息(參數(shù))然后從數(shù)據(jù)庫中得到查詢結(jié)果。很多語言都支持 XPATH 解析的功能。網(wǎng)絡(luò)應(yīng)用接收大型XML文檔,很多時候這些應(yīng)用從終端用戶和XPATH語句中取得輸入量。這些代碼的段落對XPATH注入沒有什么防御能力。 如果XPATH執(zhí)行成功,攻擊者能夠繞過認(rèn)證機制或者造成機密信息的一些損失。現(xiàn)在人們只知道很少部分的能夠被攻擊者利用的XPATH的漏洞。阻止這個攻 擊向量的唯一方法就是在給XPATH語句傳遞變量值的時候提供適當(dāng)?shù)妮斎氪_認(rèn)。類似于SQL注入,假如對數(shù)據(jù)不做驗證而直接做XPATH查詢的話。

            10. RIA瘦客戶端二進制的偽造

            豐富網(wǎng)絡(luò)應(yīng)用(RIA)使用非常豐富的UI要素比如Flash,ActiveX控件或者Applets,它使用這些要素作為網(wǎng)絡(luò)應(yīng)用的基本接 口。這個框架存在幾個安全問題。其中最主要的一個就是關(guān)于會話管理。它是在瀏覽器中運行的,并且共享相同的會話。同時,由于客戶端將下載整個二進制元件到 自己的主機,攻擊者就可以顛倒工程的那個二進制文件并且反編譯代碼。把這些二進制串打包并繞過一些包含在代碼中的認(rèn)證邏輯是有可能實現(xiàn)的。這是 WEB2.0框架下的另一個有趣的攻擊向量。因為Rich Internet Applications的組件是下載到瀏覽器本地的,攻擊者可以對二進制文件進行逆向工程,反編譯編碼,通過改動文件,跳過認(rèn)證邏輯 。

            結(jié)論

            AJAX,RIA以及網(wǎng)絡(luò)服務(wù)是WEB2.0應(yīng)用空間的三項重要的技術(shù)向量。這些技術(shù)很有前景,它們帶給桌面新的程式,加強了網(wǎng)絡(luò)應(yīng)用的整體效 率和效用。隨著這些新技術(shù)而來的是新的安全問題,忽略這些問題將會導(dǎo)致整個世界發(fā)生巨大的災(zāi)難。本文中,我們只討論了10種攻擊。但是實際上還有很多其他 的攻擊向量。對這些新的攻擊向量的最好的防御方法是增加WEB2.0的安全意識,提高代碼操作的安全性以及配置的安全性

          posted @ 2009-05-15 23:31 胡鵬 閱讀(240) | 評論 (0)編輯 收藏


          匹配中文字符的正則表達式: [\u4e00-\u9fa5]
          匹配雙字節(jié)字符(包括漢字在內(nèi)):[^\x00-\xff]
          應(yīng)用:計算字符串的長度(一個雙字節(jié)字符長度計2,ASCII字符計1)
          String.prototype.len=function(){return this.replace([^\x00-\xff]/g,"aa").length;}
          匹配空行的正則表達式:\n[\s| ]*\r
          匹配HTML標(biāo)記的正則表達式:/<(.*)>.*<\/\1>|<(.*) \/>/
          匹配首尾空格的正則表達式:(^\s*)|(\s*$)
          應(yīng)用:javascript中沒有像vbscript那樣的trim函數(shù),我們就可以利用這個表達式來實現(xiàn),如下:
          String.prototype.trim = function()
          { return this.replace(/(^\s*)|(\s*$)/g, "");
          } 利用正則表達式分解和轉(zhuǎn)換IP地址:
          下面是利用正則表達式匹配IP地址,并將IP地址轉(zhuǎn)換成對應(yīng)數(shù)值的Javascript程序:
          function IP2V(ip)
          {
          re=/(\d+)\.(\d+)\.(\d+)\.(\d+)/g //匹配IP地址的正則表達式
          if(re.test(ip))
          {
          return RegExp.$1*Math.pow(255,3))+RegExp.$2*Math.pow(255,2))+RegExp.$3*255+RegExp.$4*1
          }
          else
          {
          throw new Error("Not a valid IP address!")
          }
          }

          不過上面的程序如果不用正則表達式,而直接用split函數(shù)來分解可能更簡單,程序如下:

          var ip="10.100.20.168"
          ip=ip.split(".")
          alert("IP值是:"+(ip[0]*255*255*255+ip[1]*255*255+ip[2]*255+ip[3]*1))

          匹配Email地址的正則表達式:\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*

          匹配網(wǎng)址URL的正則表達式:http://([\w-]+\.)+[\w-]+(/[\w- ./?%&=]*)?

          利用正則表達式限制網(wǎng)頁表單里的文本框輸入內(nèi)容:

          用正則表達式限制只能輸入中文:onkeyup="value=value.replace(/[^\u4E00-\u9FA5]/g,'')"
          onbeforepaste="clipboardData.setData('text',clipboardData.getData('text').replace(/[^\u4E00-\u9FA5]/g,''))"

          用正則表達式限制只能輸入全角字符: onkeyup="value=value.replace(/[^\uFF00-\uFFFF]/g,'')"
          onbeforepaste="clipboardData.setData('text',clipboardData.getData('text').replace(/[^\uFF00-\uFFFF]/g,''))"

          用正則表達式限制只能輸入數(shù)字:onkeyup="value=value.replace(/

          [^\d]/g,'') "onbeforepaste="clipboardData.setData('text',clipboardData.getData('text').replace(/[^\d]/g,''))"

          用正則表達式限制只能輸入數(shù)字和英文:onkeyup="value=value.replace(/
          [\W]/g,'') "onbeforepaste="clipboardData.setData('text',clipboardData.getData('text').replace(/[^\d]/g,''))"

          posted @ 2009-05-15 16:06 胡鵬 閱讀(335) | 評論 (0)編輯 收藏
          僅列出標(biāo)題
          共10頁: 上一頁 1 2 3 4 5 6 7 8 9 下一頁 Last 

          導(dǎo)航

          <2025年5月>
          27282930123
          45678910
          11121314151617
          18192021222324
          25262728293031
          1234567

          統(tǒng)計

          常用鏈接

          留言簿(3)

          隨筆分類

          隨筆檔案

          agile

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 临清市| 建平县| 兖州市| 富顺县| 辛集市| 乡宁县| 慈溪市| 宁化县| 宿迁市| 克山县| 翁牛特旗| 玉田县| 肃北| 锦屏县| 新乐市| 马尔康县| 内乡县| 梓潼县| 金寨县| 佛山市| 土默特右旗| 收藏| 肇庆市| 扬中市| 格尔木市| 义乌市| 碌曲县| 菏泽市| 富源县| 安达市| 襄城县| 南岸区| 临夏县| 高安市| 肇庆市| 上思县| 东平县| 阜南县| 长治市| 应用必备| 财经|