簡單看看jdk7原始碼之java.lang包01

java小新人發表於2019-06-28

  從今天開始簡單開始讀一遍jdk的原始碼,估計這個時間會很長,慢慢啃吧。。。。(首先說一句抱歉,因為很多圖都是直接百度扣的,圖太多了不能為每一個圖附上原版連結,不好意思!)

  在網上看了很多的教程,讀原始碼有一定的順序,按照包的順序:java.lang包,java.util包,java.util.concurrent包,java.util.concurrent.atomic包,java.lang.reflect包,java.lang.annotation包,java.util.concurrent.locks包,java.io包,java.nio包,java.sql包,java.net包;

  大概數了一下,有11個包,暫時就把這11個包讀完應該就差不多了,應該可以對jdk原始碼會理解很多,而且中間可能會涉及到一些其他的知識,我也是新手,也順便學一下;

  當然也不可能把所有的方法都慢慢的去分析、去讀,重點看一些比較重要的方法看看,很多的過載方法和不常用的方法可以選擇性的省略。。。適合自己的才是最好的!比如一個方法基本上都用不到的,我們就簡單瞄兩眼就可以了,用的頻繁的方法可以去看看實現原理。

1.概述

  對於java.lang包我們可以說是用得很多了,但是一直沒有系統的整理一下,比如一個很熟悉的類Object,如果讓你說說這個類中有哪些方法啊?(親身遇到的一個面試題。。。)

  先看看這個包下常用都有些什麼類吧,借來的一個圖,1優先順序最高,4優先順序最低

1) Object 1
2) String 1
3) AbstractStringBuilder 1
4) StringBuffer 1
5) StringBuilder 1
6) Boolean 2
7) Byte 2
8) Double 2
9) Float 2
10) Integer 2
11) Long 2
12) Short 2
13) Thread 2
14) ThreadLocal 2
15) Enum 3
16) Throwable 3
17) Error 3
18) Exception 3
19) Class 4
20) ClassLoader 4
21) Compiler 4
22) System 4
23) Package 4
24) Void 4

 

  下面這個更全面,描述了java.lang包下的類主要是負責哪些方面的;

 

2.Object類

  對於這個類很熟悉吧,所有的類預設都是繼承這個類;

//任何類預設都會繼承這個類
public class Object {
    //這個方法顧名思義,就是將一些native方法註冊一下,可以簡單理解成每一個native方法都連線著一個C/C++的具體實現
    private static native void registerNatives();
    
    //此處的程式碼塊靜態會呼叫上面的這個native方法
    //所謂的native方法,就是底層用C/C++實現的,java可以有辦法去呼叫這些其他語言的方法,可以瞭解一下JNI
    static {
        registerNatives();
    }

   //這也是一個native方法,就是獲取一個類的位元組碼檔案
    public final native Class<?> getClass();

   //獲取一個類的hash值,簡單說說雜湊值,這個在map中用的比較多;其實任意物件----->通過一個hash函式計算------>得到一個很大的數字(這就是hashCode)---
   //---->這個hashCode進行取餘計算等方式,就得到陣列的下標;
    public native int hashCode();

    //可以看到這裡比較的就是兩個物件的引用,換句話說就是看看兩個物件是不是同一個物件
    public boolean equals(Object obj) {
        return (this == obj);
    }

   
    //克隆,想想現實中的克隆人。。。這裡就是克隆一個和原來物件一模一樣的物件
    //注意,克隆分為淺克隆和深度克隆,深度克隆就是克隆出來的物件和原物件無關了,而淺克隆就是和原先物件有點關係,具體的什麼關係呢?
    //我簡單說說淺克隆,原先物件中儲存了一個Person例項的引用,而克隆的物件中也儲存的是同一個Person的引用,當在克隆物件中對這個引用進行修改,原物件也會牽連。。。
    protected native Object clone() throws CloneNotSupportedException;

    //這個方法就是將當前類基本資訊以字串形式列印出來,一般就是類名+@+hashCode變為16進位制
    public String toString() {
        return getClass().getName() + "@" + Integer.toHexString(hashCode());
    }

    //多執行緒中用於隨機喚醒一個執行緒的方法,這兩個notify方法都要和wait方法一起用
    public final native void notify();

    //喚醒所有執行緒
    public final native void notifyAll();

    //讓一個執行緒休息一下一定時間,這個方法會釋放當前的鎖,想了解的可以看看我以前的部落格,或者自己看看資料
    //注意wait方法和sleep方法的區別
    public final native void wait(long timeout) throws InterruptedException;

    
    public final void wait(long timeout, int nanos) throws InterruptedException {
        if (timeout < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }

        if (nanos < 0 || nanos > 999999) {
            throw new IllegalArgumentException(
                                "nanosecond timeout value out of range");
        }

        if (nanos >= 500000 || (nanos != 0 && timeout == 0)) {
            timeout++;
        }

        wait(timeout);
    }

    //這個0可不是等待0秒啊,是等待無限長的時間,直到被喚醒
    public final void wait() throws InterruptedException {
        wait(0);
    }

   //這個方法看看就好, 最沒用的方法;主要用於jvm的垃圾回收,即使呼叫這個方法但是不保證一定立即進行回收。。。
    protected void finalize() throws Throwable { }
}

 

3.String類

  關於這個類用得很多,初學的時候最多的就是比較String,StringBuffer,StringBulider。。。我就把常用的那些方法給說一下,很少用的方法選擇性的刪除

package java.lang;

import sun.misc.FloatingDecimal;
import java.util.Arrays;


abstract class AbstractStringBuilder implements Appendable, CharSequence {
    //看來這個StringBuilder本質上也是一個位元組陣列,和String不同的是這裡沒有被final修飾
    char[] value;

    //字元陣列的容量
    int count;

    
    AbstractStringBuilder() {
    }

    //根據傳進來的引數確定字元陣列的大小
    AbstractStringBuilder(int capacity) {
        value = new char[capacity];
    }

    //返回字元陣列中實際資料的數量
    public int length() {
        return count;
    }

    //返回字元陣列的最大容量
    public int capacity() {
        return value.length;
    }

    //一下三個方法都是確保那個字元陣列大小足夠而進行的擴容操作;首先判斷你要確保新位元組陣列多大,
    //如果新陣列容量比原來陣列大,那麼就進行擴容,擴容的時候還需要進行判斷,比較系統自動擴容之後
    //的容量和你所確保的容量做個對比,如果系統擴容還達不到你的要求,那麼新位元組陣列的大小就用你確保的那個容量吧
    //最後就是將原來陣列中的資料複製到新的陣列中
    public void ensureCapacity(int minimumCapacity) {
        if (minimumCapacity > 0)
            ensureCapacityInternal(minimumCapacity);
    }

    private void ensureCapacityInternal(int minimumCapacity) {
        
        if (minimumCapacity - value.length > 0)
            expandCapacity(minimumCapacity);
    }
    
    void expandCapacity(int minimumCapacity) {
        int newCapacity = value.length * 2 + 2;
        if (newCapacity - minimumCapacity < 0)
            newCapacity = minimumCapacity;
        if (newCapacity < 0) {
            if (minimumCapacity < 0) 
                throw new OutOfMemoryError();
            newCapacity = Integer.MAX_VALUE;
        }
        value = Arrays.copyOf(value, newCapacity);
    }

    //去除陣列中多餘的位置;比如一個陣列最大容量為5,但是實際放了3個資料,空出來兩個位置,於是
    //可以將對於的兩個空位置去掉(其實就是將那是那三個資料複製到一個新的陣列中,然後改變value引用)
    public void trimToSize() {
        if (count < value.length) {
            value = Arrays.copyOf(value, count);
        }
    }

    //設定位元組陣列的長度,多餘的空位置新增'\0',這其實就是代表空字元,可以理解為null
    public void setLength(int newLength) {
        if (newLength < 0)
            throw new StringIndexOutOfBoundsException(newLength);
        ensureCapacityInternal(newLength);

        if (count < newLength) {
            for (; count < newLength; count++)
                value[count] = '\0';
        } else {
            count = newLength;
        }
    }

    //根據傳進來的索引獲取位元組陣列對應的資料
    public char charAt(int index) {
        if ((index < 0) || (index >= count))
            throw new StringIndexOutOfBoundsException(index);
        return value[index];
    }

    //擷取位元組陣列的連續的某幾個字元,放到一個新的位元組陣列中
    public void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)
    {
        if (srcBegin < 0)
            throw new StringIndexOutOfBoundsException(srcBegin);
        if ((srcEnd < 0) || (srcEnd > count))
            throw new StringIndexOutOfBoundsException(srcEnd);
        if (srcBegin > srcEnd)
            throw new StringIndexOutOfBoundsException("srcBegin > srcEnd");
        System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
    }

    //將字元陣列某個位置的字元覆蓋
    public void setCharAt(int index, char ch) {
        if ((index < 0) || (index >= count))
            throw new StringIndexOutOfBoundsException(index);
        value[index] = ch;
    }

    //傳入一個物件,將這個物件轉化為字串,然後將該字串(就是一個字元陣列)新增到當前字元陣列的末尾
    //append方法就是在當前字元陣列中後面新增所要新增的物件
    public AbstractStringBuilder append(Object obj) {
        return append(String.valueOf(obj));
    }

    //首先要確保容量足夠,再就是呼叫String類的getChars方法就是將傳進去的str從0到最後,一次複製到value位元組陣列中
    public AbstractStringBuilder append(String str) {
        if (str == null) str = "null";
        int len = str.length();
        ensureCapacityInternal(count + len);
        str.getChars(0, len, value, count);
        count += len;
        return this;
    }

    //將StringBuffer型別的字元字元陣列複製到本類的字元陣列中(首先要保證容量足夠)
    public AbstractStringBuilder append(StringBuffer sb) {
        if (sb == null)
            return append("null");
        int len = sb.length();
        ensureCapacityInternal(count + len);
        sb.getChars(0, len, value, count);
        count += len;
        return this;
    }

    //將一個字元陣列的某一段複製到本類的字元陣列當中
    public AbstractStringBuilder append(char str[], int offset, int len) {
        if (len > 0)                
            ensureCapacityInternal(count + len);
        System.arraycopy(str, offset, value, count, len);
        count += len;
        return this;
    }

    //在當前字元陣列中新增boolean字元
    public AbstractStringBuilder append(boolean b) {
        if (b) {
            ensureCapacityInternal(count + 4);
            value[count++] = 't';
            value[count++] = 'r';
            value[count++] = 'u';
            value[count++] = 'e';
        } else {
            ensureCapacityInternal(count + 5);
            value[count++] = 'f';
            value[count++] = 'a';
            value[count++] = 'l';
            value[count++] = 's';
            value[count++] = 'e';
        }
        return this;
    }

    //在當前字元陣列最後中新增一個字元
    public AbstractStringBuilder append(char c) {
        ensureCapacityInternal(count + 1);
        value[count++] = c;
        return this;
    }

    //在當前字元陣列後面新增一個int型別(4個位元組)的資料,要保證容量足夠
    //後面還有新增各種資料型別long,double,float等省略
    public AbstractStringBuilder append(int i) {
        if (i == Integer.MIN_VALUE) {
            append("-2147483648");
            return this;
        }
        int appendedLength = (i < 0) ? Integer.stringSize(-i) + 1
                                     : Integer.stringSize(i);
        int spaceNeeded = count + appendedLength;
        ensureCapacityInternal(spaceNeeded);
        Integer.getChars(i, spaceNeeded, value);
        count = spaceNeeded;
        return this;
    }

    //對一個字元陣列中某一段進行刪除,給出了起始位置和終點位置,可以看到就是利用的是陣列的複製
    //重點System.arraycopy方法,可惜這是一個native方法,看不到原始碼
    public AbstractStringBuilder delete(int start, int end) {
        if (start < 0)
            throw new StringIndexOutOfBoundsException(start);
        if (end > count)
            end = count;
        if (start > end)
            throw new StringIndexOutOfBoundsException();
        int len = end - start;
        if (len > 0) {
            System.arraycopy(value, start+len, value, start, count-end);
            count -= len;
        }
        return this;
    }

    //刪除字元陣列指定位置的字元
    public AbstractStringBuilder deleteCharAt(int index) {
        if ((index < 0) || (index >= count))
            throw new StringIndexOutOfBoundsException(index);
        System.arraycopy(value, index+1, value, index, count-index-1);
        count--;
        return this;
    }

    //目的是為了讓一個新的字元陣列,代替本字元陣列的某一段
    //其實還是通過陣列的複製
    public AbstractStringBuilder replace(int start, int end, String str) {
        if (start < 0)
            throw new StringIndexOutOfBoundsException(start);
        if (start > count)
            throw new StringIndexOutOfBoundsException("start > length()");
        if (start > end)
            throw new StringIndexOutOfBoundsException("start > end");

        if (end > count)
            end = count;
        int len = str.length();
        int newCount = count + len - (end - start);
        ensureCapacityInternal(newCount);

        System.arraycopy(value, end, value, start + len, count - end);
        str.getChars(value, start);
        count = newCount;
        return this;
    }

    //擷取字元陣列的某一段,其實就是新建了一個String型別的
    public String substring(int start, int end) {
        if (start < 0)
            throw new StringIndexOutOfBoundsException(start);
        if (end > count)
            throw new StringIndexOutOfBoundsException(end);
        if (start > end)
            throw new StringIndexOutOfBoundsException(end - start);
        return new String(value, start, end - start);
    }

    //向StringBuilder中插入一個位元組陣列的某一段,省略好多的過載insert方法
    public AbstractStringBuilder insert(int index, char[] str, int offset,
                                        int len)
    {
        if ((index < 0) || (index > length()))
            throw new StringIndexOutOfBoundsException(index);
        if ((offset < 0) || (len < 0) || (offset > str.length - len))
            throw new StringIndexOutOfBoundsException(
                "offset " + offset + ", len " + len + ", str.length "
                + str.length);
        ensureCapacityInternal(count + len);
        System.arraycopy(value, index, value, index + len, count - index);
        System.arraycopy(str, offset, value, index, len);
        count += len;
        return this;
    }

    //從前往後檢視某個字串的位置
    public int indexOf(String str) {
        return indexOf(str, 0);
    }

    //從前往後其實就是呼叫String的indexof方法
    public int indexOf(String str, int fromIndex) {
        return String.indexOf(value, 0, count,
                              str.toCharArray(), 0, str.length(), fromIndex);
    }

    //從後往前找指定字串的位置
    public int lastIndexOf(String str, int fromIndex) {
        return String.lastIndexOf(value, 0, count,
                              str.toCharArray(), 0, str.length(), fromIndex);
    }

    //逆序字元陣列,實現很簡單,不要看hasSurrogate了,反正我是沒看懂這個boolean的。。。
    public AbstractStringBuilder reverse() {
        boolean hasSurrogate = false;
        int n = count - 1;
        for (int j = (n-1) >> 1; j >= 0; --j) {
            char temp = value[j];
            char temp2 = value[n - j];
            if (!hasSurrogate) {
                hasSurrogate = (temp >= Character.MIN_SURROGATE && temp <= Character.MAX_SURROGATE)
                    || (temp2 >= Character.MIN_SURROGATE && temp2 <= Character.MAX_SURROGATE);
            }
            value[j] = temp2;
            value[n - j] = temp;
        }
        if (hasSurrogate) {
            
            for (int i = 0; i < count - 1; i++) {
                char c2 = value[i];
                if (Character.isLowSurrogate(c2)) {
                    char c1 = value[i + 1];
                    if (Character.isHighSurrogate(c1)) {
                        value[i++] = c1;
                        value[i] = c2;
                    }
                }
            }
        }
        return this;
    }

    //留給子類實現,直接列印字串
    public abstract String toString();

    //返回字元陣列
    final char[] getValue() {
        return value;
    }

}
View Code

 

 

4.StringBuilder類

  有關於這個類其實很容易,就兩層結構,final class StringBuilder extends AbstractStringBuilder,我們重點就在這個父類上,子類其實沒做什麼事,只是簡單的呼叫了父類實現的那些方法而已。。。

  AbstractStringBuilder類:

package java.lang;

import sun.misc.FloatingDecimal;
import java.util.Arrays;


abstract class AbstractStringBuilder implements Appendable, CharSequence {
    //看來這個StringBuilder本質上也是一個位元組陣列,和String不同的是這裡沒有被final修飾
    char[] value;

    //字元陣列的容量
    int count;

    
    AbstractStringBuilder() {
    }

    //根據傳進來的引數確定字元陣列的大小
    AbstractStringBuilder(int capacity) {
        value = new char[capacity];
    }

    //返回字元陣列中實際資料的數量
    public int length() {
        return count;
    }

    //返回字元陣列的最大容量
    public int capacity() {
        return value.length;
    }

    //一下三個方法都是確保那個字元陣列大小足夠而進行的擴容操作;首先判斷你要確保新位元組陣列多大,
    //如果新陣列容量比原來陣列大,那麼就進行擴容,擴容的時候還需要進行判斷,比較系統自動擴容之後
    //的容量和你所確保的容量做個對比,如果系統擴容還達不到你的要求,那麼新位元組陣列的大小就用你確保的那個容量吧
    //最後就是將原來陣列中的資料複製到新的陣列中
    public void ensureCapacity(int minimumCapacity) {
        if (minimumCapacity > 0)
            ensureCapacityInternal(minimumCapacity);
    }

    private void ensureCapacityInternal(int minimumCapacity) {
        
        if (minimumCapacity - value.length > 0)
            expandCapacity(minimumCapacity);
    }
    
    void expandCapacity(int minimumCapacity) {
        int newCapacity = value.length * 2 + 2;
        if (newCapacity - minimumCapacity < 0)
            newCapacity = minimumCapacity;
        if (newCapacity < 0) {
            if (minimumCapacity < 0) 
                throw new OutOfMemoryError();
            newCapacity = Integer.MAX_VALUE;
        }
        value = Arrays.copyOf(value, newCapacity);
    }

    //去除陣列中多餘的位置;比如一個陣列最大容量為5,但是實際放了3個資料,空出來兩個位置,於是
    //可以將對於的兩個空位置去掉(其實就是將那是那三個資料複製到一個新的陣列中,然後改變value引用)
    public void trimToSize() {
        if (count < value.length) {
            value = Arrays.copyOf(value, count);
        }
    }

    //設定位元組陣列的長度,多餘的空位置新增'\0',這其實就是代表空字元,可以理解為null
    public void setLength(int newLength) {
        if (newLength < 0)
            throw new StringIndexOutOfBoundsException(newLength);
        ensureCapacityInternal(newLength);

        if (count < newLength) {
            for (; count < newLength; count++)
                value[count] = '\0';
        } else {
            count = newLength;
        }
    }

    //根據傳進來的索引獲取位元組陣列對應的資料
    public char charAt(int index) {
        if ((index < 0) || (index >= count))
            throw new StringIndexOutOfBoundsException(index);
        return value[index];
    }

    //擷取位元組陣列的連續的某幾個字元,放到一個新的位元組陣列中
    public void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)
    {
        if (srcBegin < 0)
            throw new StringIndexOutOfBoundsException(srcBegin);
        if ((srcEnd < 0) || (srcEnd > count))
            throw new StringIndexOutOfBoundsException(srcEnd);
        if (srcBegin > srcEnd)
            throw new StringIndexOutOfBoundsException("srcBegin > srcEnd");
        System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
    }

    //將字元陣列某個位置的字元覆蓋
    public void setCharAt(int index, char ch) {
        if ((index < 0) || (index >= count))
            throw new StringIndexOutOfBoundsException(index);
        value[index] = ch;
    }

    //傳入一個物件,將這個物件轉化為字串,然後將該字串(就是一個字元陣列)新增到當前字元陣列的末尾
    //append方法就是在當前字元陣列中後面新增所要新增的物件
    public AbstractStringBuilder append(Object obj) {
        return append(String.valueOf(obj));
    }

    //首先要確保容量足夠,再就是呼叫String類的getChars方法就是將傳進去的str從0到最後,一次複製到value位元組陣列中
    public AbstractStringBuilder append(String str) {
        if (str == null) str = "null";
        int len = str.length();
        ensureCapacityInternal(count + len);
        str.getChars(0, len, value, count);
        count += len;
        return this;
    }

    //將StringBuffer型別的字元字元陣列複製到本類的字元陣列中(首先要保證容量足夠)
    public AbstractStringBuilder append(StringBuffer sb) {
        if (sb == null)
            return append("null");
        int len = sb.length();
        ensureCapacityInternal(count + len);
        sb.getChars(0, len, value, count);
        count += len;
        return this;
    }

    //將一個字元陣列的某一段複製到本類的字元陣列當中
    public AbstractStringBuilder append(char str[], int offset, int len) {
        if (len > 0)                
            ensureCapacityInternal(count + len);
        System.arraycopy(str, offset, value, count, len);
        count += len;
        return this;
    }

    //在當前字元陣列中新增boolean字元
    public AbstractStringBuilder append(boolean b) {
        if (b) {
            ensureCapacityInternal(count + 4);
            value[count++] = 't';
            value[count++] = 'r';
            value[count++] = 'u';
            value[count++] = 'e';
        } else {
            ensureCapacityInternal(count + 5);
            value[count++] = 'f';
            value[count++] = 'a';
            value[count++] = 'l';
            value[count++] = 's';
            value[count++] = 'e';
        }
        return this;
    }

    //在當前字元陣列最後中新增一個字元
    public AbstractStringBuilder append(char c) {
        ensureCapacityInternal(count + 1);
        value[count++] = c;
        return this;
    }

    //在當前字元陣列後面新增一個int型別(4個位元組)的資料,要保證容量足夠
    //後面還有新增各種資料型別long,double,float等省略
    public AbstractStringBuilder append(int i) {
        if (i == Integer.MIN_VALUE) {
            append("-2147483648");
            return this;
        }
        int appendedLength = (i < 0) ? Integer.stringSize(-i) + 1
                                     : Integer.stringSize(i);
        int spaceNeeded = count + appendedLength;
        ensureCapacityInternal(spaceNeeded);
        Integer.getChars(i, spaceNeeded, value);
        count = spaceNeeded;
        return this;
    }

    //對一個字元陣列中某一段進行刪除,給出了起始位置和終點位置,可以看到就是利用的是陣列的複製
    //重點System.arraycopy方法,可惜這是一個native方法,看不到原始碼
    public AbstractStringBuilder delete(int start, int end) {
        if (start < 0)
            throw new StringIndexOutOfBoundsException(start);
        if (end > count)
            end = count;
        if (start > end)
            throw new StringIndexOutOfBoundsException();
        int len = end - start;
        if (len > 0) {
            System.arraycopy(value, start+len, value, start, count-end);
            count -= len;
        }
        return this;
    }

    //刪除字元陣列指定位置的字元
    public AbstractStringBuilder deleteCharAt(int index) {
        if ((index < 0) || (index >= count))
            throw new StringIndexOutOfBoundsException(index);
        System.arraycopy(value, index+1, value, index, count-index-1);
        count--;
        return this;
    }

    //目的是為了讓一個新的字元陣列,代替本字元陣列的某一段
    //其實還是通過陣列的複製
    public AbstractStringBuilder replace(int start, int end, String str) {
        if (start < 0)
            throw new StringIndexOutOfBoundsException(start);
        if (start > count)
            throw new StringIndexOutOfBoundsException("start > length()");
        if (start > end)
            throw new StringIndexOutOfBoundsException("start > end");

        if (end > count)
            end = count;
        int len = str.length();
        int newCount = count + len - (end - start);
        ensureCapacityInternal(newCount);

        System.arraycopy(value, end, value, start + len, count - end);
        str.getChars(value, start);
        count = newCount;
        return this;
    }

    //擷取字元陣列的某一段,其實就是新建了一個String型別的
    public String substring(int start, int end) {
        if (start < 0)
            throw new StringIndexOutOfBoundsException(start);
        if (end > count)
            throw new StringIndexOutOfBoundsException(end);
        if (start > end)
            throw new StringIndexOutOfBoundsException(end - start);
        return new String(value, start, end - start);
    }

    //向StringBuilder中插入一個位元組陣列的某一段,省略好多的過載insert方法
    public AbstractStringBuilder insert(int index, char[] str, int offset,
                                        int len)
    {
        if ((index < 0) || (index > length()))
            throw new StringIndexOutOfBoundsException(index);
        if ((offset < 0) || (len < 0) || (offset > str.length - len))
            throw new StringIndexOutOfBoundsException(
                "offset " + offset + ", len " + len + ", str.length "
                + str.length);
        ensureCapacityInternal(count + len);
        System.arraycopy(value, index, value, index + len, count - index);
        System.arraycopy(str, offset, value, index, len);
        count += len;
        return this;
    }

    //從前往後檢視某個字串的位置
    public int indexOf(String str) {
        return indexOf(str, 0);
    }

    //從前往後其實就是呼叫String的indexof方法
    public int indexOf(String str, int fromIndex) {
        return String.indexOf(value, 0, count,
                              str.toCharArray(), 0, str.length(), fromIndex);
    }

    //從後往前找指定字串的位置
    public int lastIndexOf(String str, int fromIndex) {
        return String.lastIndexOf(value, 0, count,
                              str.toCharArray(), 0, str.length(), fromIndex);
    }

    //逆序字元陣列,實現很簡單,不要看hasSurrogate了,反正我是沒看懂這個boolean的。。。
    public AbstractStringBuilder reverse() {
        boolean hasSurrogate = false;
        int n = count - 1;
        for (int j = (n-1) >> 1; j >= 0; --j) {
            char temp = value[j];
            char temp2 = value[n - j];
            if (!hasSurrogate) {
                hasSurrogate = (temp >= Character.MIN_SURROGATE && temp <= Character.MAX_SURROGATE)
                    || (temp2 >= Character.MIN_SURROGATE && temp2 <= Character.MAX_SURROGATE);
            }
            value[j] = temp2;
            value[n - j] = temp;
        }
        if (hasSurrogate) {
            
            for (int i = 0; i < count - 1; i++) {
                char c2 = value[i];
                if (Character.isLowSurrogate(c2)) {
                    char c1 = value[i + 1];
                    if (Character.isHighSurrogate(c1)) {
                        value[i++] = c1;
                        value[i] = c2;
                    }
                }
            }
        }
        return this;
    }

    //留給子類實現,直接列印字串
    public abstract String toString();

    //返回字元陣列
    final char[] getValue() {
        return value;
    }

}
View Code

 

  

  再看子類StringBuilder那就簡單了:

package java.lang;


//我們將這個父類看了一遍這裡就簡單多了,因為基本的方法父類都已經實現了,這裡就是簡單呼叫一下
//我們就簡單看看一些重要的方法
public final class StringBuilder extends AbstractStringBuilder
    implements java.io.Serializable, CharSequence
{
    //初始化字元陣列的大小
    public StringBuilder() {
        super(16);
    }

    //也可以自定義字元陣列的大小
    public StringBuilder(int capacity) {
        super(capacity);
    }

    //初始化一個字串的時候,我們會先建立一個比字串大16的一個字元陣列,然後將字串新增進去
    public StringBuilder(String str) {
        super(str.length() + 16);
        append(str);
    }

    //沒有做什麼事,就是簡單的呼叫的一下父類的方法
    public StringBuilder append(Object obj) {
        return append(String.valueOf(obj));
    }
    public StringBuilder append(String str) {
        super.append(str);
        return this;
    }

    //擴充套件一以下,可以在後面新增StringBuilder型別的資料
    private StringBuilder append(StringBuilder sb) {
        if (sb == null)
            return append("null");
        int len = sb.length();
        int newcount = count + len;
        if (newcount > value.length)
            expandCapacity(newcount);
        sb.getChars(0, len, value, count);
        count = newcount;
        return this;
    }

    //下面省略一堆append方法,就是簡單的呼叫父類的append的各種過載方法
    //還省略一些知識簡單的呼叫父類方法的這種無聊的方法。。。
    

    
    //實現父類的toString方法,返回一個字串
    public String toString() {
        
        return new String(value, 0, count);
    }

    //下面這兩個方法挺有意思的,這兩個方法是本類獨有的,可以傳入io流,將資料寫入到位元組陣列中或者從位元組陣列中讀取資料
    private void writeObject(java.io.ObjectOutputStream s)
        throws java.io.IOException {
        s.defaultWriteObject();
        s.writeInt(count);
        s.writeObject(value);
    }

    
    private void readObject(java.io.ObjectInputStream s)
        throws java.io.IOException, ClassNotFoundException {
        s.defaultReadObject();
        count = s.readInt();
        value = (char[]) s.readObject();
    }

}
View Code

 

  

  有沒有發現,StringBuilder類和String類一樣是被final修飾了的,是屬於不可變的,關於final關鍵字修飾的知識,大概提一下,不可能指的是引用不可變,內容可以變,例如下面程式碼:

StringBuilder name = new StringBuilder("java小新人");
final StringBuilder str = name;
        
name.append("hello");
System.out.println(str);   //java小新人hello
        
str = "world";//這裡編譯器會報錯

 

 

  隨意提一下StringBuffer類,我們看看這個類:final class StringBuffer extends AbstractStringBuilder,居然也是繼承了AbstractStringBuilder這個類,那麼可以知道內部方法和StringBuilder一模一樣,那麼有什麼區別呢?隨便看一個StringBuffer中的簡單的方法,如下所示;

  很清楚的看到有個synchronized關鍵字,這個關鍵字就涉及到多執行緒的時候,同一時刻只有一個執行緒能夠訪問這個方法,想詳細瞭解synchronized關鍵字用法的可以看看我之前的部落格,或者自己看看資料也行。。。

 

5.總結

   自己看看原始碼還是很有必要的,我總是感覺要行框架中走出來,基礎始終都是基礎,我們只有把基礎搞的紮實了,學java就很容易了!

  也許我的這種看原始碼的方式不適合你,但是作為一個參考,你也可以自己去看看原始碼了,對了,當我們去複製一個java原始碼中的一個類的時候,會發現註釋的程式碼很多,那有沒有辦法可以直接刪除所有註釋呢?找了好久找到了一個java小指令碼,只需要修改一下目錄名稱就好了。。。

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;

public class Delete {
 
 
    private static int count = 0;
 
 
    /**
     * 刪除檔案中的各種註釋,包含//、/* * /等
     * @param charset 檔案編碼
     * @param file 檔案
     */
    public static void clearComment(File file, String charset) {
        try {
            //遞迴處理資料夾
            if (!file.exists()) {
                return;
            }
 
 
            if (file.isDirectory()) {
                File[] files = file.listFiles();
                for (File f : files) {
                    clearComment(f, charset); //遞迴呼叫
                }
                return;
            } else if (!file.getName().endsWith(".java")) {
                //非java檔案直接返回
                return;
            }
            System.out.println("-----開始處理檔案:" + file.getAbsolutePath());
 
 
            //根據對應的編碼格式讀取
            BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), charset));
            StringBuffer content = new StringBuffer();
            String tmp = null;
            while ((tmp = reader.readLine()) != null) {
                content.append(tmp);
                content.append("\n");
            }
            String target = content.toString();
            //String s = target.replaceAll("\\/\\/[^\\n]*|\\/\\*([^\\*^\\/]*|[\\*^\\/*]*|[^\\**\\/]*)*\\*\\/", ""); //本段正則摘自網上,有一種情況無法滿足(/* ...**/),略作修改
            String s = target.replaceAll("\\/\\/[^\\n]*|\\/\\*([^\\*^\\/]*|[\\*^\\/*]*|[^\\**\\/]*)*\\*+\\/", "");
            //System.out.println(s);
            //使用對應的編碼格式輸出
            BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), charset));
            out.write(s);
            out.flush();
            out.close();
            count++;
            System.out.println("-----檔案處理完成---" + count);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
 
 
    public static void clearComment(String filePath, String charset) {
        clearComment(new File(filePath), charset);
    }
 
 
    public static void clearComment(String filePath) {
        clearComment(new File(filePath), "UTF-8");
    }
 
 
    public static void clearComment(File file) {
        clearComment(file, "UTF-8");
    }
 
 
    public static void main(String[] args) {
        clearComment("C:\\Users\\asus\\Desktop\\jdk原始碼檔案\\03.java"); //刪除目錄下所有java檔案註釋
        //刪除某個具體檔案的註釋
        //clearComment("D:\\proj\\scm\\action\\AbcdefgAction.java");
    }
 
}
View Code

 

   後續的還會慢慢的看jdk原始碼的,最好是一遍看的時候有的方法可以敲敲程式碼試試!

 

相關文章