從今天開始簡單開始讀一遍jdk的源碼,估計這個時間會很長,慢慢啃吧。。。。(首先說一句抱歉,由於不少圖都是直接百度扣的,圖太多了不能爲每個圖附上原版連接,很差意思!)html
在網上看了不少的教程,讀源碼有必定的順序,按照包的順序: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包;java
大概數了一下,有11個包,暫時就把這11個包讀完應該就差很少了,應該能夠對jdk源碼會理解不少,並且中間可能會涉及到一些其餘的知識,我也是新手,也順便學一下;面試
固然也不可能把全部的方法都慢慢的去分析、去讀,重點看一些比較重要的方法看看,不少的重載方法和不經常使用的方法能夠選擇性的省略。。。適合本身的纔是最好的!好比一個方法基本上都用不到的,咱們就簡單瞄兩眼就能夠了,用的頻繁的方法能夠去看看實現原理。sql
1.概述數組
對於java.lang包咱們能夠說是用得不少了,可是一直沒有系統的整理一下,好比一個很熟悉的類Object,若是讓你說說這個類中有哪些方法啊?(親身遇到的一個面試題。。。)多線程
先看看這個包下經常使用都有些什麼類吧,借來的一個圖,1優先級最高,4優先級最低app
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類jvm
對於這個類很熟悉吧,全部的類默認都是繼承這個類;ide
//任何類默認都會繼承這個類 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; } }
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; } }
再看子類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(); } }
有沒有發現,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"); } }
後續的還會慢慢的看jdk源碼的,最好是一遍看的時候有的方法能夠敲敲代碼試試!