Flag之String原始碼(基於jdk1.8)
這是一個flag!
新手小白對於原始碼的困惑!
做初級開發的時候知道有原始碼,可是從來不會去主動看,因為工作上壓根用不到,而且原始碼的註釋全部是英文的,看起來壓力比較大,頭疼,每次一看見英文註釋就跳過,心理默唸,這段程式碼跟自己沒關係100遍。
近期感覺自己在業務上無法得到提高,對原來的這些基礎程式碼抱著很大的興趣,慢慢的來看一些原始碼功能!
看了幾篇文章,結合自己對於原始碼的理解之後,梳理出自己的邏輯和看原始碼的方式!
1.對於簡單的類說,例如基礎的String,Integer等 ,你要把它理解為一個個體,就像一個Person類,他是一個人的抽象類,那他有哪些人的特徵,那它就有哪些人的屬性,String類呢,他的底層結構是一個char型別的陣列,所以他有了value這個屬性
private final char value[];
2.除了一些屬性之外,String這個類被創造出來肯定是要用來實現一些功能的,例如你建立一個人出來,不會只是想著這個人就放在那啥也不幹吧,於是我們就會給他賦予各種功能,這些功能就是我們說的類裡面的方法。例如String類裡面的構造方法,作為一個“生孩子”的手段,構造方法承擔了太多,以至於我們要採用各種“外科手術”,見下圖
總結:根據以上兩點來說,java面向物件的思想都是基於抽象類來進行的,類,代表著個體,生態,功能,迴圈,有了類的抽象,一切都是類自身與類功能的組合,借用,其中涉及的各方面的功能實現都是其中為了滿足構建類生態能夠完美執行的設計精密的細節。在看原始碼的過程中,我也要本著全域性觀的視角來一一驗證我的上述猜想!
flag實現之1:String原始碼
1.String歷史由來
2.String的屬性介紹
3.String的構造方法
4.String的其他方法
1.String的歷史由來
String字元這種型別由來已久,在C++語言中,他就是字串模板類的例項,而java從C++語言中吸收了各種優秀的語言設計思想之後誕生,故而,String這個型別可能是開發者的習慣或者是方便與大眾接受等原因,沿用了C++中string>標頭檔案的標識
2.String的屬性介紹
(1) value屬性
String字串作為一個儲存字元序列的型別,他的底層實現必定是字元實現才對,所以String具有 char value[] 屬性,它的實現就是將一個個char字元拼接起來,組成一個有順序的陣列,這樣我們在使用String的物件時就能拿出一個有序的字串;
String字串的value屬性被final修飾了。意味著String類不可變,那麼為什麼會設定成不可變呢,這主要是為了安全性和效率性的考慮,我找到了一位老兄的解答,說的很有趣,特此借鑑
(2) hash屬性
hash屬性用來快取字串的雜湊碼,雜湊碼的作用主要是用於查詢的快捷性,雜湊儲存結構中確定儲存物件的儲存地址的,兩個物件的hash值相同,他們不一定是一個物件,只能說明他們在同一個雜湊的儲存結構中,也就是“同一個籃子裡”。而當兩個物件相同,那麼肯定適用於equals方法,那麼他們的hashcode值一定相同,如果equals方法被重寫,那麼hashCode方法最好也儘量重寫
(3)serialVersionUID屬性
serialVersionUID屬性適用於java序列化機制,java序列化機制通過判斷類的serialVersionUID是否相同來判斷版本是否一致。在進行反序列化時,如果JVM傳過來的位元組流彙總的serialVersionUID與本地類中的serialVersionUID進行比較,一致則進行反序列化,不一致,則出現異常,InvalidCastException。
(4)serialPersistentFields[]屬性
這個屬性是指定預設哪些欄位要被序列化,和transient相反,transient修飾的屬性申明不需要被序列化,當兩者同時存在的時候,transient會被忽略。
(5)CASE_INSENSITIVE_ORDER
java的String類忽略大小寫敏感比較器,主要是在compareToIgnoreCase(String str)方法中需要使用到。
3.String的構造方法
String的原始碼中有16中構造方法,有些方法已經過時不被建議呼叫,其中就有兩項使用@Deprecated修飾
(1) String(byte [], int, int, int)和String(byte[], int)方法已經被不推薦使用,這兩個方法的官方說明如下
String(byte[] ascii, int hibyte, int offset, int count) 已棄用 此方法無法將位元組正確轉換為字元。 從JDK 1.1開始,首選的方式是通過String建構函式獲取Charset ,字符集名稱,或使用平臺的預設字符集。 String(byte[] ascii, int hibyte) 已棄用 此方法無法將位元組正確轉換為字元。 從JDK 1.1開始,首選的方法是通過String建構函式獲取Charset ,字符集名稱,或者使用平臺的預設字符集。
(2)其他的構造方法
無參構造:String(),預設值是一個空的字串陣列;
public String() { this.value = "".value; }
單個引數構造:①String(String original),②String(char value[]),③String(byte bytes[]),④String(StringBuffer buffer),⑥String(StringBuilder builder)
第一種就是直接將原來的String物件的value和hash值複製到新的String物件中,第二種是直接將value陣列複製到新的String物件value裡面,第三種是將byte陣列複製到value值中,內部其實是呼叫了String(byte bytes[], int offset, int length)方法來使用預設的字符集解碼byte陣列構造新的String物件,第四第五種只是在第二種方法上增加了一層轉化,相容兩種String的工具類物件初始化String
多個引數構造:
String(char value[], int offset, int count):此方法獲取value陣列從第offset為開始節點,長度為count的陣列,賦值給value,構造成新的String物件
String(int[] codePoints, int offset, int count):此方法是將int型的資料轉化成char陣列並且根據offset和count初始化新的String物件
String(byte bytes[], int offset, int length, String charsetName):此方法是將bytes陣列根據傳入的字符集名稱轉化成char陣列並且根據offset和count初始化String物件
String(byte bytes[], int offset, int length, Charset charset):同上,只是此方法是根據java內建的字符集型別進行初始化
以下幾種方法與上面大同小異,只是入參稍有不同
String(byte bytes[], String charsetName) String(byte bytes[], Charset charset) String(byte bytes[], int offset, int length) String(char[] value, boolean share)
在String的構造方法中多次呼叫checkBounds(byte[] bytes, int offset, int length)方法,主要是為了防止在對byte[] 做擷取的時候發生陣列下標越界問題,此為校驗方法,當傳入的初始化引數不正確,將會丟擲StringIndexOutOfBoundsException異常。
4.String的其他方法