Java API學習筆記(一)

衣舞晨風發表於2016-07-31

 1. 不要重複初始化變數

預設情況下,呼叫類的建構函式時,java會把變數初始化成確定的值,所有的物件被設定成null,整數變數設定成0,float和double變數設定成0.0,邏輯值設定成false。當一個類從另一個類派生時,這一點尤其應該注意,因為用new關鍵字建立一個物件時,建構函式鏈中的所有建構函式都會被自動呼叫。這裡有個注意,給成員變數設定初始值但需要呼叫其他方法的時候,最好放在一個方法比如initXXX()中,因為直接呼叫某方法賦值可能會因為類尚未初始化而拋空指標異常,如:public int state = this.getState();


 2. 字串內部化

由String類維護一個初始為空的字串的物件池,當intern方法被呼叫時,如果物件池中已經包含這一個相等的字串物件則返回物件池中的例項,否則新增字串到物件池並返回該字串的引用。

在對被內部快取的字串進行比較時,可以直接使用“==”操作符,而不是更加耗時的equals方法。

 /**
     * Returns a canonical representation for the string object.
     * <p>
     * A pool of strings, initially empty, is maintained privately by the
     * class {@code String}.
     * <p>
     * When the intern method is invoked, if the pool already contains a
     * string equal to this {@code String} object as determined by
     * the {@link #equals(Object)} method, then the string from the pool is
     * returned. Otherwise, this {@code String} object is added to the
     * pool and a reference to this {@code String} object is returned.
     * <p>
     * It follows that for any two strings {@code s} and {@code t},
     * {@code s.intern() == t.intern()} is {@code true}
     * if and only if {@code s.equals(t)} is {@code true}.
     * <p>
     * All literal strings and string-valued constant expressions are
     * interned. String literals are defined in section 3.10.5 of the
     * <cite>The Java™ Language Specification</cite>.
     *
     * @return  a string that has the same contents as this string, but is
     *          guaranteed to be from a pool of unique strings.
     */
    public native String intern();
小注:

        一個Native Method就是一個java呼叫非java程式碼的介面。一個Native Method是這樣一個java的方法:該方法的實現由非java語言實現,比如C。

3、String物件  == 與equals的區別

        equals原始碼如下:

  /**
     * Compares this string to the specified object.  The result is {@code
     * true} if and only if the argument is not {@code null} and is a {@code
     * String} object that represents the same sequence of characters as this
     * object.
     *
     * @param  anObject
     *         The object to compare this {@code String} against
     *
     * @return  {@code true} if the given object represents a {@code String}
     *          equivalent to this string, {@code false} otherwise
     *
     * @see  #compareTo(String)
     * @see  #equalsIgnoreCase(String)
     */
    public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String anotherString = (String)anObject;
            int n = value.length;
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }
      從程式碼中可以看出:

      1、String類對Object類的equals進行了重寫

       Object類equals方法如下: 

 /**
     * Indicates whether some other object is "equal to" this one.
     * <p>
     * The {@code equals} method implements an equivalence relation
     * on non-null object references:
     * <ul>
     * <li>It is <i>reflexive</i>: for any non-null reference value
     *     {@code x}, {@code x.equals(x)} should return
     *     {@code true}.
     * <li>It is <i>symmetric</i>: for any non-null reference values
     *     {@code x} and {@code y}, {@code x.equals(y)}
     *     should return {@code true} if and only if
     *     {@code y.equals(x)} returns {@code true}.
     * <li>It is <i>transitive</i>: for any non-null reference values
     *     {@code x}, {@code y}, and {@code z}, if
     *     {@code x.equals(y)} returns {@code true} and
     *     {@code y.equals(z)} returns {@code true}, then
     *     {@code x.equals(z)} should return {@code true}.
     * <li>It is <i>consistent</i>: for any non-null reference values
     *     {@code x} and {@code y}, multiple invocations of
     *     {@code x.equals(y)} consistently return {@code true}
     *     or consistently return {@code false}, provided no
     *     information used in {@code equals} comparisons on the
     *     objects is modified.
     * <li>For any non-null reference value {@code x},
     *     {@code x.equals(null)} should return {@code false}.
     * </ul>
     * <p>
     * The {@code equals} method for class {@code Object} implements
     * the most discriminating possible equivalence relation on objects;
     * that is, for any non-null reference values {@code x} and
     * {@code y}, this method returns {@code true} if and only
     * if {@code x} and {@code y} refer to the same object
     * ({@code x == y} has the value {@code true}).
     * <p>
     * Note that it is generally necessary to override the {@code hashCode}
     * method whenever this method is overridden, so as to maintain the
     * general contract for the {@code hashCode} method, which states
     * that equal objects must have equal hash codes.
     *
     * @param   obj   the reference object with which to compare.
     * @return  {@code true} if this object is the same as the obj
     *          argument; {@code false} otherwise.
     * @see     #hashCode()
     * @see     java.util.HashMap
     */
    public boolean equals(Object obj) {
        return (this == obj);
    }

      2、String類的equals是用來比較兩個物件內部的內容是否相等的。


      ==:是用來判斷兩個物件的地址是否相同,即是否是指相同一個物件。比較的是真正意義上的指標操作。


4、List.subList方法使用注意

  在使用集合中,可能常常需要取集合中的某一部分子集來進行一下操作,於是subList這個方法就映入我們的眼簾,毫不猶豫地使用。
	public static void main(final String[] args) {
		List<Object> lists = new ArrayList<Object>();

		lists.add("1");
		lists.add("2");
		lists.add("3");
		lists.add("4");

		List<Object> tempList = lists.subList(2, lists.size());

		tempList.add("6");

		System.out.println(tempList); // 1

		System.out.println(lists); // 2
	} 
     程式碼初步寫好後,可能我們想達到的效果是:往集合lists的子集合tempList中新增一個元素6,而原有的集合保持不變。
    即到達這樣的效果:lists = [1, 2, 3, 4],tempList = [3, 4, 6]。但是我們看到實際的結果確是lists裡邊也新增了元素6。
          
    這是怎麼一會事呢,通過查詢java原始碼我們可以看到:
 
 /**
     * Returns a view of the portion of this list between the specified
     * {@code fromIndex}, inclusive, and {@code toIndex}, exclusive.  (If
     * {@code fromIndex} and {@code toIndex} are equal, the returned list is
     * empty.)  The returned list is backed by this list, so non-structural
     * changes in the returned list are reflected in this list, and vice-versa.
     * The returned list supports all of the optional list operations.
     *
     * <p>This method eliminates the need for explicit range operations (of
     * the sort that commonly exist for arrays).  Any operation that expects
     * a list can be used as a range operation by passing a subList view
     * instead of a whole list.  For example, the following idiom
     * removes a range of elements from a list:
     * <pre>
     *      list.subList(from, to).clear();
     * </pre>
     * Similar idioms may be constructed for {@link #indexOf(Object)} and
     * {@link #lastIndexOf(Object)}, and all of the algorithms in the
     * {@link Collections} class can be applied to a subList.
     *
     * <p>The semantics of the list returned by this method become undefined if
     * the backing list (i.e., this list) is <i>structurally modified</i> in
     * any way other than via the returned list.  (Structural modifications are
     * those that change the size of this list, or otherwise perturb it in such
     * a fashion that iterations in progress may yield incorrect results.)
     *
     * @throws IndexOutOfBoundsException {@inheritDoc}
     * @throws IllegalArgumentException {@inheritDoc}
     */
    public List<E> subList(int fromIndex, int toIndex) {
        subListRangeCheck(fromIndex, toIndex, size);
        return new SubList(this, 0, fromIndex, toIndex);
    }

    static void subListRangeCheck(int fromIndex, int toIndex, int size) {
        if (fromIndex < 0)
            throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
        if (toIndex > size)
            throw new IndexOutOfBoundsException("toIndex = " + toIndex);
        if (fromIndex > toIndex)
            throw new IllegalArgumentException("fromIndex(" + fromIndex +
                                               ") > toIndex(" + toIndex + ")");
    }
     那麼new SubList(this, 0, fromIndex, toIndex)是個什麼鬼?
 SubList(AbstractList<E> parent,
                int offset, int fromIndex, int toIndex) {
            this.parent = parent;
            this.parentOffset = fromIndex;
            this.offset = offset + fromIndex;
            this.size = toIndex - fromIndex;
            this.modCount = ArrayList.this.modCount;
        }       
     從程式碼中可以看出來SubList其實通過指標是指向父list(將原有的list物件給快取到SubList類物件的一個屬性中去了),所以彼此之間會相互影響。SubList類的add/remove等修改元素的方法:
public void add(int index, E e) {
            rangeCheckForAdd(index);
            checkForComodification();
            parent.add(parentOffset + index, e);
            this.modCount = parent.modCount;
            this.size++;
        }

        public E remove(int index) {
            rangeCheck(index);
            checkForComodification();
            E result = parent.remove(parentOffset + index);
            this.modCount = parent.modCount;
            this.size--;
            return result;
        }
  因此,當我們使用子集合tempList進行元素的修改操作時,會影響原有的list集合。所以在使用subList方法時,一定要想清楚,是否需要對子集合進行修改元素而不影響原有的list集合。
  如果需要對子集合的元素進行修改操作而不需要影響原集合時,我們可以使用以下方法進行處理:
 
public static void main(final String[] args) {  
    List<Object> lists = new ArrayList<Object>();  
  
    lists.add("1");  
    lists.add("2");  
    lists.add("3");  
    lists.add("4");  
  
    //注意這裡是和本文頂部的程式碼不同的....   
    List<Object> tempList = new ArrayList<Object>(lists.subList(2, lists.size()));  
  
    tempList.add("6");  
  
    System.out.println(tempList); // 1   
  
    System.out.println(lists); // 2   
}  

  結果如下:


5、返回零長度的陣列或者集合,而不是null 

        如果一個方法的返回值型別是集合或者陣列 ,如果在方法內部需要返回的集合或者陣列是零長度的,也就是沒有實際物件在裡面,我們也應該放回一個零長度的陣列或者集合,而不是返回null。如果返回了null,客戶端程式設計師就要檢測返回的是不是null,然後才能進行下一步操作,否則就會引發NullPointException。但是如果是返回的的是空陣列或者集合,就不會再後續的使用這個物件上,引發空指標異常,我們可以根據程式碼的行為和表現,來判斷陣列和集合是不是為空。

6、ArrayList  Vector LinkedList

      ArrayList 和Vector是採用陣列方式儲存資料,此陣列元素數大於實際儲存的資料以便增加和插入元素,都允許直接序號索引元素,但是插入資料要設計到陣列元素移動等記憶體操作,所以索引資料快插入資料慢,Vector由於使用了synchronized方法(執行緒安全)所以效能上比ArrayList要差,LinkedList使用雙向連結串列實現儲存,按序號索引資料需要進行向前或向後遍歷,但是插入資料時只需要記錄本項的前後項即可,所以插入數度較快!
      如果資料較為穩定,不易發生新增操作,那麼可以考慮ArrayList ,如果容易發生修改,可以考慮使用linkedlist。
      java集合類關係圖(圖片來自:點選開啟連結):

7、RandomAccess 介面

         RandomAccess 介面是一個標誌介面,本身並沒有提供任何方法,任務凡是通過呼叫 RandomAccess 介面的物件都可以認為是支援快速隨機訪問的物件。此介面的主要目的是標識那些可支援快速隨機訪問的 List 實現。任何一個基於陣列的 List 實現都實現了 RaodomAccess 介面,而基於連結串列的實現則都沒有。因為只有陣列能夠進行快速的隨機訪問,而對連結串列的隨機訪問需要進行連結串列的遍歷。因此,此介面的好處是,可以在應用程式中知道正在處理的 List 物件是否可以進行快速隨機訪問,從而針對不同的 List 進行不同的操作,以提高程式的效能。
        JDK中說的很清楚,在對List特別是Huge size的List的遍歷演算法中,要儘量來判斷是屬於RandomAccess(如ArrayList)還是Sequence List (如LinkedList),因為適合RandomAccess List的遍歷演算法,用在Sequence List上就差別很大。
 if (list instance of RandomAccess) {
        for(int m = 0; m < list.size(); m++){}
    }else{
        Iterator iter = list.iterator();
        while(iter.hasNext()){}
    }

8、Vertor Hashtable

       單執行緒應儘量使用HashMap、ArrayList,HashTable、Vector等使用了同步機制,降低了效能。
       如果希望在多執行緒情況下使用列表,可以使用Collections中提供的synchronizedList(List list),多執行緒情況下使用hashMap,可以使用Collections中提供的synchronizedMap(Map<K,V> m)

9、HasMapHashSet

  HashSet底層是採用HasMap實現的  HasMap儲存的是  鍵值對。


小注:
Set是一種不包括重複元素的Collection。它維持它自己的內部排序,所以隨機訪問沒有任何意義。與List一樣,它同樣執行null的存在但是僅有一個。由於Set介面的特殊性,所有傳入Set集合中的元素都必須不同,同時要注意任何可變物件,如果在對集合中元素進行操作時,導致e1.equals(e2)==true,則必定會產生某些問題。實現了Set介面的集合有:EnumSet、HashSet、TreeSet。
         HashSet堪稱查詢速度最快的集合,因為其內部是以HashCode來實現的。它內部元素的順序是由雜湊碼來決定的,所以它不保證set 的迭代順序;特別是它不保證該順序恆久不變。

10、String、StringBuffer和StringBuilder

String注意點:
1:當使用任何方式來建立一個字串物件s時,Java執行時(執行中JVM)會拿著這個X在String池中找是否存在內容相同的字串物件,如果不存在,則在池中建立一個字串s,否則,不在池中新增。
2:Java中,只要使用new關鍵字來建立物件,則一定會(在堆區或棧區)建立一個新的物件。
3:使用直接指定或者使用純字串串聯來建立String物件,則僅僅會檢查維護String池中的字串,池中沒有就在池中建立一個,有則罷了!但絕不會在堆疊區再去建立該String物件。
4:使用包含變數的表示式來建立String物件,則不僅會檢查維護String池,而且會在堆疊區建立一個String物件。


StringBuffer:字串變數(Synchronized,即執行緒安全)。如果要頻繁對字串內容進行修改,出於效率考慮最好使用StringBuffer,如果想轉成String型別,可以呼叫StringBuffer的toString()方法。

StringBuilder:字串變數(非執行緒安全)。在內部,StringBuilder物件被當作是一個包含字元序列的變長陣列。
小注:
StringBuilder比StringBuffer大約快10%到15%。

作者:jiankunking 出處:http://blog.csdn.net/jiankunking


相關文章