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

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

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

    posts - 13,comments - 70,trackbacks - 1
    有別人寫好的筆記,不用自己費神寫了。對于看過Effective Java的偶而忘記某個條目,看看筆記或許能記起來。
     
    Creating and Destroying Object
    Item 1:考慮用靜態工廠方法替代構造器
    例如:public static Boolean valueOf(boolean b)
         {
              return (b?Boolean.TRUE:Boolean.FALSE);
         }
    這樣的好處是方法有名字,并且它可以復用對象,不像構造器每次調用都產生新的對象。其次它還可以返回返回類型的子類。不好的地方是如果沒有public or protected構造器的類將不能被繼承。還有就是靜態工廠方法的名字和其他的靜態方法名字不容易區分。
    Item 2:通過添加私有構造器來加強單例屬性(singletom property)
    例如:public class Hello
                {
                      private static final Hello Instance = new Hell();
                      private Hello()
                      {}
                       
                        public static Hello getInstance()
                          {
                         return Instance;
                         }
                }
    這個私有構造器只能在內部被使用,確保了單例模式!
    Item 3:避免創建重復的對象
    對不可修改的對象盡量進行復用,這樣效率和性能都會提高。例如如果循環100次String s = new String("hello")將創建100個對象 循環100次String s = "hello";則只創建了一個對象。很好的進行了復用。
    Item 4:用私有構造器來避免被實例化
    例如public UtilityClass
    {
       private UtilityClass()
       {}
    ///
    }
    通常那些工具類是這么設計的
    Item 5:消除絕對的對象引用
         雖然java中使用gc來管理內存,但是如果不注意的話也會產生“內存泄漏”。例如下面的程序
    public class Stack
    {
     private Object[] elements;
     private int size = 0;
     
     public Stack(int i)
     {
      this.elements = new Object[i];
     }
     
     public void push(Object e)
     {
      ensure();
      elements[size++] = e;
     }
     
     public Object pop()
     {
      if(size == 0)
      {
       ////
      }
     
      return elements[size--];
     }
     
     private void ensure()
     {
      ////
     }
    }
    標記的地方存在著內存泄漏的問題,因為當他被彈出棧的時候,它也沒有成為可回收的垃圾對象,Stack維護著他們的絕對的引用。將不能更改。改進的方法是如下的寫法
     public Object pop()
     {
      if(size == 0)
      {
       ////
      }
      Object obj = elements[--size];
      elements[size] = null;
     
      return obj;
     }
     但是切忌不要濫用null。
    Item 6:避免finalizer
    垃圾回收器是低線程級別運行的且不能被強迫執行。System.gc()只是建議垃圾回收器收集垃圾,它可不一定馬上運行,而且垃圾回收器運行的時候會掛起其他線程導致程序停止響應。推薦使用的方法類似于
    InputStream is = null;
    try
    {
          is = /////;
    }
    finally
    {
          is.close();
    }
    Methods Common to All Objects
    item 7:當你覆蓋equals方法的時候一定要遵守general contact
       覆蓋equals的時候一定要加倍的小心,其實最好的辦法就是不覆蓋這個方法。比如在下面的情況下就可以不覆蓋
       1這個類的每個實例都是唯一的,例如Thread類
       2 如果你不關心這個類是否該提供一個測試邏輯相等的方法
       3超類已經覆蓋了equals方法,并且它合適子類使用
       4如果這個類是private或者是package-private的,并且你確信他不會被調用
       但是當我們要為這個類提供區分邏輯相等和引用相等的方法的時候,我們就必須要覆蓋這個方法了。例如String類,Date類等,覆蓋的時候我們一定要遵從general contact,說白了就是一個合同。合同的主要內容是
       1.x.equals(x)必須返回true
       2.x.equals(y)當且僅當y.equals(x)返回true的時候返回true
       3.x.equals(y)返回true,y.equals(z)返回true,那么x.equals(z)必須返回true
       4.如果沒有任何修改得話 那么多次調用x.equals(y)的返回值應該不變
       5.任何時候非空的對象x,x.equals(null)必須返回false
    下面是作者的建議如何正確的覆蓋equals方法
    1.  用==檢查是否參數就是這個對象的引用
    2.  用instanceof判斷參數的類型是否正確
    3.  把參數轉換成合適的類型
    4.  比較類的字段是不是匹配
    例如:
    public boolean equals(Object o)
    {
           if(o== this) return true;
           if(!(o instanceof xxxx) return false;
           xxx in = (xxx)o;
           return ……..
    }
    最后一點要注意的時候不要提供這樣的方法public boolean equals(MyClass o)這樣是重載并不是覆蓋Object的equals方法
    item 8 :當你覆蓋equals的時候必須覆蓋hashCode方法
        這點必須切忌,不然在你和hash-based集合打交道的時候,錯誤就會出現了。關鍵問題在于一定要滿足相等的對象必須要有相等的hashCode。如果你在PhoneNumber類中覆蓋了equals方法,但是沒有覆蓋hashCode方法,那么當你做如下操作的時候就會出現問題了。
    Map m = new HashMap();
    m.put(new PhoneNumber(408,863,3334),”ming”)
    當你調用m.get(new PhoneNumber(408,863,3334))的時候你希望得到ming但是你卻得到了null,為什么呢因為在整個過程中有兩個PhoneNumber的實例,一個是put一個是get,但是他們兩個邏輯相等的實例卻得到不同的hashCode那么怎么可以取得以前存入的ming呢。
     
    Item 9:永遠覆蓋toString方法
        在Object的toString方法返回的形式是Class的類型加上@加上16進制的hashcode。你最好在自己的類中提供toString方法更好的表述實例的信息,不然別人怎么看得明白呢。
    Item 10:覆蓋clone()方法的時候一定要小心
        一個對象要想被Clone,那么要實現Clone()接口,這個接口沒有定義任何的方法,但是如果你不實現這個接口的話,調用clone方法的時候會出現CloneNotSupportedException,這就是作者叫做mixin的接口類型。通常clone()方法可以這樣覆蓋
    public Object clone()
    {
    try
    {
                  return super.clone();
    }
    catch(CloneNotSupportedException e)
    {}
    }
    但是當你要clone的類里面含有可修改的引用字段的時候,那么你一定要把整個類的藍圖進行復制,如果對你clone得到的對象進行修改的時候還會影響到原來的實例,那么這是不可取的。所以應該這樣clone()
    public Object clone() throws CloneNotSupportedException
    {
           Stack Result  = (Stack)super.clone();
           Result.elements = (Object[])elements.clone();
           Return result;
    }
    其中elements是stack類中可修改的引用字段,注意如果elements是final的話我們就無能為力了,因為不能給他重新賦值了.其實如果不是必須的話,根本就不用它最好。
     
    Item 11:考慮適當的時候覆蓋Comparable接口
         Thinking in java上說的更清楚,這里不多少了。
        越來越發現這是一本難得的好書,Java程序員不看這本書的話真是很遺憾。本章講述的是類和接口相關的問題。這幾個Item都非常重要.
    Item 12:把類和成員的可訪問范圍降到最低
        好的模塊設計應該盡最大可能封裝好自己的內部信息,這樣可以把模塊之間的耦合程度降到最低。開發得以并行,無疑這將加快開發的速度,便于系統地維護。Java中通過訪問控制符來解決這個問題。
    public表示這個類在任何范圍都可用。
    protected表示只有子類和包內的類可以使用
    private-package(default)表示在包內可用
    private表示只有類內才可以用
    你在設計一個類的時候應該盡量的按照4321得順序設計。如果一個類只是被另一個類使用,那么應該考慮把它設計成這個類的內部類。通常public的類不應該有public得字段,不過我們通常會用一個類來定義所有的常量,這是允許的。不過必須保證這些字段要么是基本數據類型要么引用指向的對象是不可修改的。不然他們將可能被修改。例如下面的定義中data就是不合理的,后面兩個沒有問題。
    public class Con
    {
          public static final int[] data = {1,2,3};// it is bad
          public static final String hello = "world";
          public static final int i = 1;
    }
    Item 13:不可修改的類更受青睞
        不可修改的類意思是他們一經創建就不會改變,例如String類。他們的設計、實現都很方便,安全性高——它們是線程安全的。設計不可修改類有幾點規則:
    不要提供任何可以修改對象的方法
    確保沒有方法能夠被覆蓋,可以通過把它聲明為final
    所有字段設計成final
    所有字段設計成private
    確保外部不能訪問到類的可修改的組件
    不可修改類也有個缺點就是創建不同值得類的時候要創建不同的對象,String就是這樣的。通常有個解決的辦法就是提供一個幫助類來彌補,例如StringBuffer類。
    Item 14:化合(合成)比繼承更值得考慮
          實現代碼重用最重要的辦法就是繼承,但是繼承破壞了封裝,導致軟件的鍵壯性不足。如果子類繼承了父類,那么它從父類繼承的方法就依賴父類的實現,一旦他改變了會導致不可預測的結果。作者介紹了InstrumentedHashSet作為反例進行說明,原因就是沒有明白父類的方法實現。作者給出的解決辦法是通過化合來代替繼承,用包裝類和轉發方法來解決問題。把想擴展的類作為本類的一個private final得成員變量。把方法參數傳遞給這個成員變量并得到返回值。這樣做的缺點是這樣的類不適合回掉框架。繼承雖然好,我們卻不應該濫用,只有我們能確定它們之間是is-a得關系的時候才使用。
    Item 15:如果要用繼承那么設計以及文檔都要有質量保證,否則就不要用它
        為了避免繼承帶來的問題,你必須提供精確的文檔來說明覆蓋相關方法可能出現的問題。在構造器內千萬不要調用可以被覆蓋的方法,因為子類覆蓋方法的時候會出現問題。
    import java.util.*;
    public class SubClass extends SuperClass
    {
     private final Date date;
     
     public SubClass()
     {
      date = new Date();
     }
     
     public void m()
     {
      System.out.println(date);
     }
     
     public static void main(String[] args)
     {
      SubClass s = new SubClass();
      s.m();
     }
     
    }
    class SuperClass
    {
     public SuperClass()
     {
      m();
     }
     
     public void m()
     {
     
     }
    }
    由于在date被初始化之前super()已經被調用了,所以第一次輸出null而不是當前的時間。
    由于在Clone()或者序列化的時候非常類似構造器的功能,因此readObject()和clone()方法內最好也不要包括能被覆蓋的方法。
    Item 16:在接口和抽象類之間優先選擇前者
          接口和抽象類都用來實現多態,不過我們應該優先考慮用接口。知道嗎?James說過如果要讓他重新設計java的話他會把所有都設計成接口的。抽象類的優點是方便擴展,因為它是被繼承的,并且方法可以在抽象類內實現,接口則不行。
    Item 17:接口只應該用來定義類型
          接口可以這樣用的 Collection c = new xxxx();這是我們最常用的。不要把接口用來做其他的事情,比如常量的定義。你應該定義一個類,里面包含public final static 得字段。
    Item 18: 在靜態和非靜態內部類之間選擇前者
          如果一個類被定義在其他的類內部那么它就是嵌套類,可以分為靜態內部類、非靜態內部類和匿名類。
       static member class 得目的是為enclosing class服務,如果還有其他的目的,就應該把它設計成top-level class。nonstatic member class是和enclosing class instance關聯的,如果不需要訪問enclosing class instance的話應該把它設計成static得,不然會浪費時間和空間。anonymous class是聲明和初始化同時進行的。可以放在代碼的任意位置。典型應用是Listener 和process object例如Thread。
        由于以前學過C語言,所以對C還是蠻有感情,而JAVA和C又有很多相似之處,很多從C轉過來學習JAVA的兄弟,可能一開始都不是很適應,因為很多在C里面的結構在JAVA里面都不能使用了,所以下面我們來介紹一下C語言結構的替代。
          Item 19:用類代替結構
         JAVA剛面世的時候,很多C程序員都認為用類來代替結構現在太復雜,代價太大了,但是實際上,如果一個JAVA的類退化到只包含一個數據域的話,這樣的類與C語言的結構大致是等價的。
          比方說下面兩個程序片段:
          class Point
          {
           private float x;
           private float y;
          }
          實際上這段代碼和C語言的結構基本上沒什么區別,但是這段代碼恐怕是眾多OO設計Fans所不齒的,因為它沒有體現封裝的優異性,沒有體現面向對象設計的優點,當一個域被修改的時候,你不可能再采取任何輔助的措施了,那我們再來看一看采用包含私有域和共有訪問方法的OO設計代碼段:
         class Point
          {
           private float x;
           private float y;
           public Point(float x,float y)
           {
                 this.x=x;
                 this.y=y;
           }
            public float getX(){retrun x;}
            public float getY(){return y;}
            public void setX(float x){this.x=x;}
            public void setY(float y){this.y=y;}
          }
            單從表面上看,這段代碼比上面那個多了很多行,還多了很多函數,但是仔細想一下,這樣的OO設計,似乎更人性化,我們可以方面的對值域進行提取,修改等操作,而不直接和值域發生關系,這樣的代碼不僅讓人容易讀懂,而且很安全,還吸取了面向對象程序設計的靈活性,試想一下,如果一個共有類暴露它的值域,那么想要在將來的版本中進行修改是impossible的,因為共有類的客戶代碼已經遍布各處了。
    需要提醒一點的是,如果一個類是包級私有的,或者是一個私有的嵌套類,則直接暴露其值域并無不妥之處。
    Item 20:用類層次來代替聯合
    我們在用C語言來進行開發的時候,經常會用到聯合這個概念,比如:
           typedef struct{
         double length;
         double width;    
    }rectangleDimensions_t;
    那我們在JAVA里面沒有聯合這個概念,那我們用什么呢?對!用繼承,這也是JAVA最吸引我的地方之一,它可以使用更好的機制來定義耽擱數據類型,在Bruce Eckel的Thinking in java里面也多次提到了一個和形狀有關的例子,我們可以先籠統的定義一個抽象類,即我們通常所指的超類,每個操作定義一個抽象的方法,其行為取決于標簽的值,如果還有其他的操作不依賴于標簽的值,則把操作變成根類(繼承的類)中的具體方法。
    這樣做的最重要的優點是:類層次提供了類型的安全性。
    其次代碼非常明了,這也是OO設計的優點。
    而且它很容易擴展,即使是面向多個方面的工作,能夠同樣勝任。
    最后它可以反映這些類型之間本質上的層次關系,從而允許更強的靈活性,以便編譯時類型檢查。
    Item 21:用類來代替enum結構
    Java程序設計語言提出了類型安全枚舉的模式來替代enum結構,它的基本思想很簡單:定義一個類來代表枚舉類型的單個元素,并且不提供任何公有的構造函數,相反,提供公有靜態final類,使枚舉類型中的每一個常量都對應一個域。
    類型安全枚舉類型的一個缺點是,裝載枚舉類的和構造常量對象時,需要一定的時間和空間開銷,除非是在資源很受限制的設備比如蜂窩電哈和烤面包機上,否則在實際中這個問題不會被考慮。
     總之,類型安全枚舉類型明顯優于int類型,除非實在一個枚舉類型主要被用做一個集合元素,或者主要用在一個資源非常不受限的環境下,否則類型安全枚舉類型的缺點都不成問題,依次,在要求使用一個枚舉類型的環境下,我們首先應考慮類型安全枚舉類型模式。
    Item 22:用類和接口來代替函數指針
    眾所周知,JAVA語言和C的最大區別在于,前者去掉了指針,小生第一次接觸JAVA的時候覺得好不習慣,因為突然一下子沒了指針,覺得好不方面啊,C語言的精髓在于其指針的運用,而JAVA卻把它砍掉了,讓人好生郁悶,不過隨著時間的推移,我漸漸明白了用類和接口的應用也同樣可以提供同樣的功能,我們可以直接定義一個這樣一個類,他的方法是執行其他方法上的操作,如果一個類僅僅是導出這樣一個方法,那么它實際上就是一個指向該方法的指針,舉個例子:
    class StringLengthComprator{
    public int compare(String s1,String s2)
    {
    return s1.length()-s2.length();
    }
    }
    這個類導出一個帶兩個字符串的方法,它是一個用于字符串比較的具體策略。它是無狀態的,沒有域,所以,這個類的所有實例在功能上都是等價的,可以節省不必要的對象創建開銷。但是我們不好直接把這個類傳遞給可戶使用,因為可戶無法傳遞任何其他的比較策略。相反,我們可以定義一個接口,即我們在設計具體策略類的時候還需要定義一個策略接口:
          public interface Comparator{
               public int compare(Object o1,Object o2);
    }
      我們完全可以依照自己的需要來定義它。
    具體的策略類往往使用匿名類聲明。
    在JAVA中,我們為了實現指針的模式,聲明一個接口來表示該策略,并且為每個具體策略聲明一個實現了該接口的類,如果一個具體策略只被使用一次的話,那么通常使用匿名類來聲明和實例化這個具體策略類,如果一個策略類反復使用,那么它的類通常是一個私有的的靜態成員類。
    下面我們來討論一下有關方法設計的幾個方面,下面說的幾個要點大多數都是應用在構造函數中,當然也使用于普通方法,我們追求的依然是程序的可用性,健壯性和靈活性。
    Item 23:檢查參數的有效性
    非公有的方法我們應該用斷言的方法來檢查它的參數,而不是使用通常大家所熟悉的檢查語句來檢測。如果我們使用的開發平臺是JDK1.4或者更高級的平臺,我們可以使用assert結構;否則我們應該使用一種臨時的斷言機制。
    有些參數在使用過程中是先保存起來,然后在使用的時候再進行調用,構造函數正是這種類型的一種體現,所以我們通常對構造函數參數的有效性檢查是非常仔細的。
    Item 24:需要時使用保護性拷貝
    眾所周知,JAVA在代碼安全性方面較C/C++有顯著的提高,緩沖區溢出,數組越界,非法指針等等,我們的JAVA都有一個很完善的機制來進行免疫,但是這并不代表我們不必去考慮JAVA的安全性,即便在安全的語言,如果不采取措施,還是無法使自己與其他類隔開。假設類的客戶會盡一切手段來破壞這個類的約束條件,在這樣的前提下,你必須從保護性的方面來考慮設計程序。通過大量的程序代碼研究我們得出這樣的結論:對于構造性函數的每個可變參數進行保護性拷貝是必要的。需要注意的是,保護性拷貝是在檢查參數的有效性之前 進行的,并且有效性檢查是針對拷貝之后的對象,而不是原始的對象。對于“參數類型可以被不可信方子類化”的情況,不要用clone方法來進行參數的保護性拷貝。
    對于參數的保護性拷貝并不僅僅在于非可變類,當我們編寫一個函數或者一個構造函數的時候,如果它要接受客戶提供的對象,允許該對象進入到內部數據結構中,則有必要考慮一下,客戶提供的對象是否是可變的,如果是,則要考慮其變化的范圍是否在你的程序所能容納的范圍內,如果不是,則要對對象進行保護性拷貝,并且讓拷貝之后的對象而不是原始對象進入到數據結構中去。當然最好的解決方法是使用非可變的對象作為你的對象內部足見,這樣你就可以不必關心保護性拷貝問題了。):
    Item 25:謹慎使用設計方法的原型
    (1)謹慎的選擇方法的名字:即要注意首先要是易于理解的,其次還要與該包中的其他方法的命名風格相一致,最后當然要注意取一個大眾所認可的名字。
    (2)不要追求提供便利的方法:每一個方法都應該提供其應具備的功能點,對于接口和類來方法不要過多,否則會對學習使用維護等等方面帶來許多不必要的麻煩,對于每一個類型所支持的每一個動作,都提供一個功能完全的方法,只有一個方法過于頻繁的使用時,才考慮為它提供一個快捷方法。
    (3)避免過長的參數列表:通常在實踐中,我們以三個參數作為最大值,參數越少越好,類型相同的長參數列尤其影響客戶的使用,兩個方法可以避免過長的參數這樣的情況發生,一是把一個方法分解成多個,每一個方法只要求使用這些參數的一個子集;二是創建輔助類,用來保存參數的聚集,這些輔助類的狀態通常是靜態的。
    對于參數類型,優先使用接口而不是類。
    這樣做的目的是避免影響效能的拷貝操作。
    謹慎的使用函數對象。
    創建函數對象最容易的方法莫過于使用匿名類,但是那樣會帶來語法上混亂,并且與內聯的控制結構相比,這樣也會導致功能上的局限性。
    Item 26:謹慎的使用重載
    到底是什么造成了重載機制的混淆算法,這是個爭論的話題,一個安全而保守的方法是,永遠不要導出兩個具有相同參數數目的重載方法。而對于構造函數來說,一個類的多個構造函數總是重載的,在某些情況下,我們可以選擇靜態工廠,但是對于構造函數來說這樣做并不總是切合實際的。
    當涉及到構造函數時,遵循這條建議也許是不可能的,但我們應該極力避免下面的情形:
    同一組參數只需要經過類型的轉換就可以傳遞給不同的重載方法。如果這樣做也不能避免的話,我們至少要保證一點:當傳遞同樣的參數時,所有的重載方法行為一致。如果不能做到這一點,程序員就不能有效的使用方法或者構造函數。
    Item 27:返回零長度的數組而不是null
    因為這樣做的原因是編寫客戶程序的程序員可能忘記寫這種專門的代碼來處理null返回值。沒有理由從一個取數組值的方法中返回null,而不是返回一個零長度數組。
    Item 28:為所有導出的API元素編寫文檔注釋
    不愛寫注釋可能是大多數程序員新手的通病(包括偶哈~),但是如果想要一個API真正可用,就必須寫一個文檔來說明它,保持代碼和文檔的同步是一件比較煩瑣的事情,JAVA語言環境提供了javadoc工具,從而使這個煩瑣的過程變得容易,這個工具可以根據源代碼自動產生API文檔。
    為了正確得編寫API文檔,我們必須每一個被導出的類,接口,構造函數,方法和域聲明之前加一個文檔注釋。
    每一個方法的文檔注釋應該見解的描述它和客戶之間的約定。
    我們接下來討論一下Java語言的細節,包括局部變量的處理,庫的使用,以及兩種不是語言本身提供的機制的使用等等一些大家平時可能忽略的問題。
    Item 29:將局部變量的作用域最小化
    和C語言要求局部變量必須被生命在代碼的開始處相比,Java程序設計語言寬松得多,它允許你在代碼的任何位置聲明。要想使一個局部變量的作用域最小化,最高小的技術是在第一次需要使用它的地方聲明,變量的作用域是從聲明它的地方開始到這個聲明做在的代碼塊的結束位止,如果我們把變量的聲明和代碼的使用位置分開的過大,那么對于讀這段代碼的人來說,是很不幸的。
    我們幾乎都是在一個局部變量聲明的地方同時給它初始化,注意這是很重要的,甚至有時候,如果我們的初始化應該推遲到下一個代碼的位置,我們同時應該把聲明也往后延遲。這條規則唯一的例外是try-catch這個語句,因為如果一個變量被方法初始化,那么這個方法很有可能拋出一個異常,那我們最常用的方法就是把它置于try塊的內部去進行初始化。由此我們可以得出,for循環優于while循環,我們在能使用for循環的地方盡量使用for而不使用while,因為for循環是完全獨立的,所以重用循環變量名字不會有任何傷害。
    最后我們要記住的是盡量把我們的函數寫的小而集中,這樣才能真正組做到”最小化局部變量的作用域”這一要旨。
    Item 30:了解和使用庫
    使用標準庫,我們可以充分利用編寫這些庫的Java專家的知識,以及在你之前其他人的使用經驗,這就是所謂站在巨人的肩膀上看世界吧~
    在每一個Java平臺的發行版本里面,都會有許多新的包的加入,和這些更新保持一直是值得的,比如說我們J2ME的開發,在MIDP 1.0的時代,我們要寫個Game還要自己動手寫工具類,現在MIDP2.0推出之后,大多數寫游戲的人都覺得方便了很多,因為在這個版本里面加入了游戲包,為我們的開發節省了大量的人力物力。
    Item 31:如果想要知道精確的答案,就要避免使用double和float
         對于金融行業來說,對數據的嚴整性要求是很高的,不容半點馬虎,那大家都知道再我們的Java語言里面有兩個浮點數類型的變量float和double,可能大家會認為他們的精度對于金融行業這樣對數字敏感的行業來說,已經夠用了,但是在開發當中,我們要盡量少使用double和float,因為讓他們精確的表達0.1是不可能的。那我們如何解決這個問題呢,答案是使用BigDecimal,int或者long進行貨幣計算。在這里對大家的忠告是:對于商務運算,我們盡量使用BigDecimal,對于性能要求較高的地方,我們有能力自己處理十進制的小數點,數值不太大的時候,我們可以使用int或者long,根據自己的需要來判定具體使用哪一個,如果范圍超過了18位數,那我們必須使用BigDecimal。
    Item 32:如果其他類型更適合,則盡量避免使用字符串
         在偶看到這條建議之前,我就很喜歡用字符串,不管在什么場合下,先String了再說,但是實際上很多情況下,我們要根據實際情況來判定到底使用什么類型,而且字符串不適合替代枚舉類型,類型安全枚舉類型和int值都比字符串更適合用來表示枚舉類型的常量。字符串也不適合替代聚集類型,有一個更好的方法就是簡單的寫一個類來描述這個數據集,通常是一個私有的靜態成員類最好。字符串也不適合代替能力表,總而言之,如果可以適合更加適合的數據類型,或者可以編寫更加適當的數據類型,那么應該避免使用字符串來表示對象。
    Item 33:了解字符串的連接功能
    我們經常在使用System.out.println()的時候,往括號里寫一串用“+”連接起來的字符串,這是我們最常見的,但是這個方法并不適合規模較大的情形,為連接N個字符串而重復地使用字符串連接操作符,要求N的平方級的時間,這是因為字符串是非可變的,這就導致了在字符串進行連接的時候,前后兩者都要拷貝,這個時候我們就提倡使用StingBuffer替代String。
    Item 34:通過接口引用對象
    通俗的說就是盡量優先使用接口而不是類來引用對象,如果有合適的接口存在那么對使用參數,返回值,變量域都應該使用接口類型養成使用接口作為對象的習慣,會使程序變得更加靈活。
    如果沒有合適的接口,那么,用類而不是接口來引用一個對象,是完全合適的。
    Item 35:接口優先于映像機制
    java.lang.relect提供了“通過程序來訪問關于已裝載的類的信息”,由此,我們可以通過一個給定的Class實例,獲得Constructor,Method和Field實例。
    映像機制允許一個類使用另一個類,即使當前編譯的時候后者還不存在,但是這種能力也要付出代價:
    我們損失了了編譯時類型檢查的好處,而且要求執行映像訪問的代碼非常笨拙和冗長,并且在性能上大大損失。
    通常,普通應用在運行時刻不應以映像方式訪問對象。
    Item 36:謹慎的使用本地方法
    JNI允許Java應用程序調用本地方法,所謂本地方法是指用本地程序設計語言(如C,C++)來編寫的特殊方法,本地方法可以在本地語言執行任何計算任務,然后返回到Java程序設計語言中。但是隨著JDK1.3及后續版本的推出這種通過使用本地方法來提高性能的方法已不值得提倡,因為現在的JVM越來越快了,而且使用本地方法有一些嚴重的缺點,比如使Java原本引以為傲的安全性蕩然無存,總之在使用本地方法的時候要三思。
    Item 37:謹慎使用優化
    不要因為性能而犧牲合理的代碼結構,努力編寫好的程序而不是快的程序,但是避免那些限制性能的設計決定,同時考慮自己設計的API決定的性能后果,為了獲得更好的性能而對API進行修改這也是一個非常不好的想法,通常我們在做優化之后,都應該對優化的程度進行一些測量。
    Item 38:遵守普遍接受的命名慣例
    Java有一套比較完善的命名慣例機制,大部分包含在《The Java Language Specification》,嚴格得講這些慣例分成兩類,字面的和語法的。
    字面涉及包,類,接口,方法和域,語法的命名慣例比較靈活,所以爭議更大,字面慣例是非常直接和明確的,而語法慣例則相對復雜,也很松散。但是有一個公認的做法是:“如果長期養成的習慣用法與此不同的話,請不要盲目遵從
    Item 12:把類和成員的可訪問范圍降到最低
        好的模塊設計應該盡最大可能封裝好自己的內部信息,這樣可以把模塊之間的耦合程度降到最低。開發得以并行,無疑這將加快開發的速度,便于系統地維護。Java中通過訪問控制符來解決這個問題。
    public表示這個類在任何范圍都可用。
    protected表示只有子類和包內的類可以使用
    private-package(default)表示在包內可用
    private表示只有類內才可以用
    你在設計一個類的時候應該盡量的按照4321得順序設計。如果一個類只是被另一個類使用,那么應該考慮把它設計成這個類的內部類。通常public的類不應該有public得字段,不過我們通常會用一個類來定義所有的常量,這是允許的。不過必須保證這些字段要么是基本數據類型要么引用指向的對象是不可修改的。不然他們將可能被修改。例如下面的定義中data就是不合理的,后面兩個沒有問題。
    public class Con
    {
          public static final int[] data = {1,2,3};// it is bad
          public static final String hello = "world";
          public static final int i = 1;
    }
    Item 13:不可修改的類更受青睞
        不可修改的類意思是他們一經創建就不會改變,例如String類。他們的設計、實現都很方便,安全性高——它們是線程安全的。設計不可修改類有幾點規則:
    不要提供任何可以修改對象的方法
    確保沒有方法能夠被覆蓋,可以通過把它聲明為final
    所有字段設計成final
    所有字段設計成private
    確保外部不能訪問到類的可修改的組件
    不可修改類也有個缺點就是創建不同值得類的時候要創建不同的對象,String就是這樣的。通常有個解決的辦法就是提供一個幫助類來彌補,例如StringBuffer類。
    Item 14:化合(合成)比繼承更值得考慮
          實現代碼重用最重要的辦法就是繼承,但是繼承破壞了封裝,導致軟件的鍵壯性不足。如果子類繼承了父類,那么它從父類繼承的方法就依賴父類的實現,一旦他改變了會導致不可預測的結果。作者介紹了InstrumentedHashSet作為反例進行說明,原因就是沒有明白父類的方法實現。作者給出的解決辦法是通過化合來代替繼承,用包裝類和轉發方法來解決問題。把想擴展的類作為本類的一個private final得成員變量。把方法參數傳遞給這個成員變量并得到返回值。這樣做的缺點是這樣的類不適合回掉框架。繼承雖然好,我們卻不應該濫用,只有我們能確定它們之間是is-a得關系的時候才使用。
    Item 15:如果要用繼承那么設計以及文檔都要有質量保證,否則就不要用它
        為了避免繼承帶來的問題,你必須提供精確的文檔來說明覆蓋相關方法可能出現的問題。在構造器內千萬不要調用可以被覆蓋的方法,因為子類覆蓋方法的時候會出現問題。
    import java.util.*;
    public class SubClass extends SuperClass
    {
     private final Date date;
     
     public SubClass()
     {
      date = new Date();
     }
     
     public void m()
     {
      System.out.println(date);
     }
     
     public static void main(String[] args)
     {
      SubClass s = new SubClass();
      s.m();
     }
     
    }
    class SuperClass
    {
     public SuperClass()
     {
      m();
     }
     
     public void m()
     {
     
     }
    }
    由于在date被初始化之前super()已經被調用了,所以第一次輸出null而不是當前的時間。
    由于在Clone()或者序列化的時候非常類似構造器的功能,因此readObject()和clone()方法內最好也不要包括能被覆蓋的方法。
    Item 16:在接口和抽象類之間優先選擇前者
          接口和抽象類都用來實現多態,不過我們應該優先考慮用接口。知道嗎?James說過如果要讓他重新設計java的話他會把所有都設計成接口的。抽象類的優點是方便擴展,因為它是被繼承的,并且方法可以在抽象類內實現,接口則不行。
    Item 17:接口只應該用來定義類型
          接口可以這樣用的 Collection c = new xxxx();這是我們最常用的。不要把接口用來做其他的事情,比如常量的定義。你應該定義一個類,里面包含public final static 得字段。
    Item 18: 在靜態和非靜態內部類之間選擇前者
          如果一個類被定義在其他的類內部那么它就是嵌套類,可以分為靜態內部類、非靜態內部類和匿名類。
       static member class 得目的是為enclosing class服務,如果還有其他的目的,就應該把它設計成top-level class。nonstatic member class是和enclosing class instance關聯的,如果不需要訪問enclosing class instance的話應該把它設計成static得,不然會浪費時間和空間。anonymous class是聲明和初始化同時進行的。可以放在代碼的任意位置。典型應用是Listener 和process object例如Thread。
        由于以前學過C語言,所以對C還是蠻有感情,而JAVA和C又有很多相似之處,很多從C轉過來學習JAVA的兄弟,可能一開始都不是很適應,因為很多在C里面的結構在JAVA里面都不能使用了,所以下面我們來介紹一下C語言結構的替代。
    Item 19:用類代替結構
          JAVA剛面世的時候,很多C程序員都認為用類來代替結構現在太復雜,代價太大了,但是實際上,如果一個JAVA的類退化到只包含一個數據域的話,這樣的類與C語言的結構大致是等價的。
          比方說下面兩個程序片段:
          class Point
          {
           private float x;
           private float y;
          }
          實際上這段代碼和C語言的結構基本上沒什么區別,但是這段代碼恐怕是眾多OO設計Fans所不齒的,因為它沒有體現封裝的優異性,沒有體現面向對象設計的優點,當一個域被修改的時候,你不可能再采取任何輔助的措施了,那我們再來看一看采用包含私有域和共有訪問方法的OO設計代碼段:
          class Point
          {
           private float x;
           private float y;
           public Point(float x,float y)
           {
                 this.x=x;
                 this.y=y;
           }
            public float getX(){retrun x;}
            public float getY(){return y;}
            public void setX(float x){this.x=x;}
            public void setY(float y){this.y=y;}
          }
            單從表面上看,這段代碼比上面那個多了很多行,還多了很多函數,但是仔細想一下,這樣的OO設計,似乎更人性化,我們可以方面的對值域進行提取,修改等操作,而不直接和值域發生關系,這樣的代碼不僅讓人容易讀懂,而且很安全,還吸取了面向對象程序設計的靈活性,試想一下,如果一個共有類暴露它的值域,那么想要在將來的版本中進行修改是impossible的,因為共有類的客戶代碼已經遍布各處了。
    需要提醒一點的是,如果一個類是包級私有的,或者是一個私有的嵌套類,則直接暴露其值域并無不妥之處。
    Item 20:用類層次來代替聯合
    我們在用C語言來進行開發的時候,經常會用到聯合這個概念,比如:
           typedef struct{
         double length;
         double width;    
    }rectangleDimensions_t;
    那我們在JAVA里面沒有聯合這個概念,那我們用什么呢?對!用繼承,這也是JAVA最吸引我的地方之一,它可以使用更好的機制來定義耽擱數據類型,在Bruce Eckel的Thinking in java里面也多次提到了一個和形狀有關的例子,我們可以先籠統的定義一個抽象類,即我們通常所指的超類,每個操作定義一個抽象的方法,其行為取決于標簽的值,如果還有其他的操作不依賴于標簽的值,則把操作變成根類(繼承的類)中的具體方法。
    這樣做的最重要的優點是:類層次提供了類型的安全性。
    其次代碼非常明了,這也是OO設計的優點。
    而且它很容易擴展,即使是面向多個方面的工作,能夠同樣勝任。
    最后它可以反映這些類型之間本質上的層次關系,從而允許更強的靈活性,以便編譯時類型檢查。
    Item 21:用類來代替enum結構
    Java程序設計語言提出了類型安全枚舉的模式來替代enum結構,它的基本思想很簡單:定義一個類來代表枚舉類型的單個元素,并且不提供任何公有的構造函數,相反,提供公有靜態final類,使枚舉類型中的每一個常量都對應一個域。
    類型安全枚舉類型的一個缺點是,裝載枚舉類的和構造常量對象時,需要一定的時間和空間開銷,除非是在資源很受限制的設備比如蜂窩電哈和烤面包機上,否則在實際中這個問題不會被考慮。
     總之,類型安全枚舉類型明顯優于int類型,除非實在一個枚舉類型主要被用做一個集合元素,或者主要用在一個資源非常不受限的環境下,否則類型安全枚舉類型的缺點都不成問題,依次,在要求使用一個枚舉類型的環境下,我們首先應考慮類型安全枚舉類型模式。
    Item 22:用類和接口來代替函數指針
     class StringLengthComprator{
    public int compare(String s1,String s2)
    {
    return s1.length()-s2.length();
    }
    }
    這個類導出一個帶兩個字符串的方法,它是一個用于字符串比較的具體策略。它是無狀態的,沒有域,所以,這個類的所有實例在功能上都是等價的,可以節省不必要的對象創建開銷。但是我們不好直接把這個類傳遞給可戶使用,因為可戶無法傳遞任何其他的比較策略。相反,我們可以定義一個接口,即我們在設計具體策略類的時候還需要定義一個策略接口:
          public interface Comparator{
               public int compare(Object o1,Object o2);
    }
      我們完全可以依照自己的需要來定義它。
    在JAVA中,我們為了實現指針的模式,聲明一個接口來表示該策略,并且為每個具體策略聲明一個實現了該接口的類,如果一個具體策略只被使用一次的話,那么通常使用匿名類來聲明和實例化這個具體策略類,如果一個策略類反復使用,那么它的類通常是一個私有的的靜態成員類。
    下面我們來討論一下有關方法設計的幾個方面,下面說的幾個要點大多數都是應用在構造函數中,當然也使用于普通方法,我們追求的依然是程序的可用性,健壯性和靈活性。
    Item 23:檢查參數的有效性
    非公有的方法我們應該用斷言的方法來檢查它的參數,而不是使用通常大家所熟悉的檢查語句來檢測。如果我們使用的開發平臺是JDK1.4或者更高級的平臺,我們可以使用assert結構;否則我們應該使用一種臨時的斷言機制。
    有些參數在使用過程中是先保存起來,然后在使用的時候再進行調用,構造函數正是這種類型的一種體現,所以我們通常對構造函數參數的有效性檢查是非常仔細的。
    Item 24:需要時使用保護性拷貝
    眾所周知,JAVA在代碼安全性方面較C/C++有顯著的提高,緩沖區溢出,數組越界,非法指針等等,我們的JAVA都有一個很完善的機制來進行免疫,但是這并不代表我們不必去考慮JAVA的安全性,即便在安全的語言,如果不采取措施,還是無法使自己與其他類隔開。假設類的客戶會盡一切手段來破壞這個類的約束條件,在這樣的前提下,你必須從保護性的方面來考慮設計程序。通過大量的程序代碼研究我們得出這樣的結論:對于構造性函數的每個可變參數進行保護性拷貝是必要的。需要注意的是,保護性拷貝是在檢查參數的有效性之前 進行的,并且有效性檢查是針對拷貝之后的對象,而不是原始的對象。對于“參數類型可以被不可信方子類化”的情況,不要用clone方法來進行參數的保護性拷貝。
    對于參數的保護性拷貝并不僅僅在于非可變類,當我們編寫一個函數或者一個構造函數的時候,如果它要接受客戶提供的對象,允許該對象進入到內部數據結構中,則有必要考慮一下,客戶提供的對象是否是可變的,如果是,則要考慮其變化的范圍是否在你的程序所能容納的范圍內,如果不是,則要對對象進行保護性拷貝,并且讓拷貝之后的對象而不是原始對象進入到數據結構中去。當然最好的解決方法是使用非可變的對象作為你的對象內部足見,這樣你就可以不必關心保護性拷貝問題了。):
    Item 25:謹慎使用設計方法的原型
    (1)謹慎的選擇方法的名字:即要注意首先要是易于理解的,其次還要與該包中的其他方法的命名風格相一致,最后當然要注意取一個大眾所認可的名字。
    (2)不要追求提供便利的方法:每一個方法都應該提供其應具備的功能點,對于接口和類來方法不要過多,否則會對學習使用維護等等方面帶來許多不必要的麻煩,對于每一個類型所支持的每一個動作,都提供一個功能完全的方法,只有一個方法過于頻繁的使用時,才考慮為它提供一個快捷方法。
    (3)避免過長的參數列表:通常在實踐中,我們以三個參數作為最大值,參數越少越好,類型相同的長參數列尤其影響客戶的使用,兩個方法可以避免過長的參數這樣的情況發生,一是把一個方法分解成多個,每一個方法只要求使用這些參數的一個子集;二是創建輔助類,用來保存參數的聚集,這些輔助類的狀態通常是靜態的。
    對于參數類型,優先使用接口而不是類。
    這樣做的目的是避免影響效能的拷貝操作。
    謹慎的使用函數對象。
    創建函數對象最容易的方法莫過于使用匿名類,但是那樣會帶來語法上混亂,并且與內聯的控制結構相比,這樣也會導致功能上的局限性。
    Item 26:謹慎的使用重載
    到底是什么造成了重載機制的混淆算法,這是個爭論的話題,一個安全而保守的方法是,永遠不要導出兩個具有相同參數數目的重載方法。而對于構造函數來說,一個類的多個構造函數總是重載的,在某些情況下,我們可以選擇靜態工廠,但是對于構造函數來說這樣做并不總是切合實際的。
    當涉及到構造函數時,遵循這條建議也許是不可能的,但我們應該極力避免下面的情形:
    同一組參數只需要經過類型的轉換就可以傳遞給不同的重載方法。如果這樣做也不能避免的話,我們至少要保證一點:當傳遞同樣的參數時,所有的重載方法行為一致。如果不能做到這一點,程序員就不能有效的使用方法或者構造函數。
    Item 27:返回零長度的數組而不是null
    因為這樣做的原因是編寫客戶程序的程序員可能忘記寫這種專門的代碼來處理null返回值。沒有理由從一個取數組值的方法中返回null,而不是返回一個零長度數組。
    Item 28:為所有導出的API元素編寫文檔注釋
    不愛寫注釋可能是大多數程序員新手的通病(包括偶哈~),但是如果想要一個API真正可用,就必須寫一個文檔來說明它,保持代碼和文檔的同步是一件比較煩瑣的事情,JAVA語言環境提供了javadoc工具,從而使這個煩瑣的過程變得容易,這個工具可以根據源代碼自動產生API文檔。
    為了正確得編寫API文檔,我們必須每一個被導出的類,接口,構造函數,方法和域聲明之前加一個文檔注釋。
    每一個方法的文檔注釋應該見解的描述它和客戶之間的約定。
    我們接下來討論一下Java語言的細節,包括局部變量的處理,庫的使用,以及兩種不是語言本身提供的機制的使用等等一些大家平時可能忽略的問題。
    Item 29:將局部變量的作用域最小化
    和C語言要求局部變量必須被生命在代碼的開始處相比,Java程序設計語言寬松得多,它允許你在代碼的任何位置聲明。要想使一個局部變量的作用域最小化,最高小的技術是在第一次需要使用它的地方聲明,變量的作用域是從聲明它的地方開始到這個聲明做在的代碼塊的結束位止,如果我們把變量的聲明和代碼的使用位置分開的過大,那么對于讀這段代碼的人來說,是很不幸的。
    我們幾乎都是在一個局部變量聲明的地方同時給它初始化,注意這是很重要的,甚至有時候,如果我們的初始化應該推遲到下一個代碼的位置,我們同時應該把聲明也往后延遲。這條規則唯一的例外是try-catch這個語句,因為如果一個變量被方法初始化,那么這個方法很有可能拋出一個異常,那我們最常用的方法就是把它置于try塊的內部去進行初始化。由此我們可以得出,for循環優于while循環,我們在能使用for循環的地方盡量使用for而不使用while,因為for循環是完全獨立的,所以重用循環變量名字不會有任何傷害。
    最后我們要記住的是盡量把我們的函數寫的小而集中,這樣才能真正組做到”最小化局部變量的作用域”這一要旨。
    Item 30:了解和使用庫
    使用標準庫,我們可以充分利用編寫這些庫的Java專家的知識,以及在你之前其他人的使用經驗,這就是所謂站在巨人的肩膀上看世界吧~
    在每一個Java平臺的發行版本里面,都會有許多新的包的加入,和這些更新保持一直是值得的,比如說我們J2ME的開發,在MIDP 1.0的時代,我們要寫個Game還要自己動手寫工具類,現在MIDP2.0推出之后,大多數寫游戲的人都覺得方便了很多,因為在這個版本里面加入了游戲包,為我們的開發節省了大量的人力物力。
    Item 31:如果想要知道精確的答案,就要避免使用double和float
         對于金融行業來說,對數據的嚴整性要求是很高的,不容半點馬虎,那大家都知道再我們的Java語言里面有兩個浮點數類型的變量float和double,可能大家會認為他們的精度對于金融行業這樣對數字敏感的行業來說,已經夠用了,但是在開發當中,我們要盡量少使用double和float,因為讓他們精確的表達0.1是不可能的。那我們如何解決這個問題呢,答案是使用BigDecimal,int或者long進行貨幣計算。在這里對大家的忠告是:對于商務運算,我們盡量使用BigDecimal,對于性能要求較高的地方,我們有能力自己處理十進制的小數點,數值不太大的時候,我們可以使用int或者long,根據自己的需要來判定具體使用哪一個,如果范圍超過了18位數,那我們必須使用BigDecimal。
    Item 32:如果其他類型更適合,則盡量避免使用字符串
         在偶看到這條建議之前,我就很喜歡用字符串,不管在什么場合下,先String了再說,但是實際上很多情況下,我們要根據實際情況來判定到底使用什么類型,而且字符串不適合替代枚舉類型,類型安全枚舉類型和int值都比字符串更適合用來表示枚舉類型的常量。字符串也不適合替代聚集類型,有一個更好的方法就是簡單的寫一個類來描述這個數據集,通常是一個私有的靜態成員類最好。字符串也不適合代替能力表,總而言之,如果可以適合更加適合的數據類型,或者可以編寫更加適當的數據類型,那么應該避免使用字符串來表示對象。
    Item 33:了解字符串的連接功能
    我們經常在使用System.out.println()的時候,往括號里寫一串用“+”連接起來的字符串,這是我們最常見的,但是這個方法并不適合規模較大的情形,為連接N個字符串而重復地使用字符串連接操作符,要求N的平方級的時間,這是因為字符串是非可變的,這就導致了在字符串進行連接的時候,前后兩者都要拷貝,這個時候我們就提倡使用StingBuffer替代String。
    Item 34:通過接口引用對象
    通俗的說就是盡量優先使用接口而不是類來引用對象,如果有合適的接口存在那么對使用參數,返回值,變量域都應該使用接口類型養成使用接口作為對象的習慣,會使程序變得更加靈活。
    如果沒有合適的接口,那么,用類而不是接口來引用一個對象,是完全合適的。
    Item 35:接口優先于映像機制
    java.lang.relect提供了“通過程序來訪問關于已裝載的類的信息”,由此,我們可以通過一個給定的Class實例,獲得Constructor,Method和Field實例。
    映像機制允許一個類使用另一個類,即使當前編譯的時候后者還不存在,但是這種能力也要付出代價:
    我們損失了了編譯時類型檢查的好處,而且要求執行映像訪問的代碼非常笨拙和冗長,并且在性能上大大損失。
    通常,普通應用在運行時刻不應以映像方式訪問對象。
    Item 36:謹慎的使用本地方法
    JNI允許Java應用程序調用本地方法,所謂本地方法是指用本地程序設計語言(如C,C++)來編寫的特殊方法,本地方法可以在本地語言執行任何計算任務,然后返回到Java程序設計語言中。但是隨著JDK1.3及后續版本的推出這種通過使用本地方法來提高性能的方法已不值得提倡,因為現在的JVM越來越快了,而且使用本地方法有一些嚴重的缺點,比如使Java原本引以為傲的安全性蕩然無存,總之在使用本地方法的時候要三思。
    Item 37:謹慎使用優化
    不要因為性能而犧牲合理的代碼結構,努力編寫好的程序而不是快的程序,但是避免那些限制性能的設計決定,同時考慮自己設計的API決定的性能后果,為了獲得更好的性能而對API進行修改這也是一個非常不好的想法,通常我們在做優化之后,都應該對優化的程度進行一些測量。
    Item 38:遵守普遍接受的命名慣例
    Java有一套比較完善的命名慣例機制,大部分包含在《The Java Language Specification》,嚴格得講這些慣例分成兩類,字面的和語法的。
    字面涉及包,類,接口,方法和域,語法的命名慣例比較靈活,所以爭議更大,字面慣例是非常直接和明確的,而語法慣例則相對復雜,也很松散。但是有一個公認的做法是:“如果長期養成的習慣用法與此不同的話,請不要盲目遵從
    posted on 2005-09-25 15:24 落花飛雪 閱讀(1922) 評論(0)  編輯  收藏 所屬分類: Java
    主站蜘蛛池模板: 免费人成网站永久| 亚洲国产成人99精品激情在线| 美美女高清毛片视频黄的一免费| 久久久久国色AV免费看图片| 亚洲精品成人网站在线播放| 91麻豆国产免费观看| 亚洲视频一区在线观看| 最近免费中文在线视频| 亚洲欧洲日产国码在线观看| 午夜国产精品免费观看| 国产精品亚洲精品青青青| 妞干网在线免费观看| 亚洲精品成a人在线观看夫| 国产成人免费a在线视频app| 美女18毛片免费视频| 亚洲人成国产精品无码| 丁香花在线观看免费观看图片| 亚洲AV永久无码区成人网站 | 免费一级毛片不卡在线播放| 亚洲av日韩专区在线观看| 免费人成在线观看视频播放 | 亚洲AV成人精品日韩一区| 日韩精品免费电影| 一级毛片大全免费播放| 亚洲精品无码永久在线观看你懂的 | 久久精品国产亚洲Aⅴ蜜臀色欲| 中文在线免费看视频| 久久精品亚洲中文字幕无码麻豆| 一二三四在线观看免费高清中文在线观看| 亚洲综合国产成人丁香五月激情| 免费人成激情视频| 美女被cao网站免费看在线看| 亚洲制服丝袜第一页| 亚洲av麻豆aⅴ无码电影| 久久精品电影免费动漫| 成人区精品一区二区不卡亚洲| 亚洲裸男gv网站| 中文字幕成人免费视频| 毛片亚洲AV无码精品国产午夜| 亚洲成AV人片在线观看无码| 免费看成人AA片无码视频羞羞网|