string類總結第一部分函數介紹

  在前面幾章,看了整個String類的源碼,給每個方法都行寫了註釋,但是太過凌亂,今天我就把String類的方法整理歸納,然後再講一下String類比較難以理解的部分

  特此聲明:本文篇幅較大,涵蓋知識點較多,請耐着性子讀下去,畢竟寫文章不易,寫知識性文章更加不易!

第一部分:函數介紹

  這是第一部分的內容,由於String的函數較多,我將他們分爲四大類,分別是構造性函數、轉換性函數、功能性函數以及私有函數

  • 私有函數:主要是把屬性以及一些私有方法列出來
  • 構造性函數:也就是字符串的構造器
  • 轉換性函數:負責字符串和其他類型之間的轉換,比如說valueOf
  • 功能性函數:其實除了構造函數和轉換函數,其他函數都具些特別常用的功能,我們經常使用功能函數,所有我將他們羅列出來(ps:重點)

私有函數:

  如果你仔細看源代碼的話,會發現每個私有函數都會在代碼中被頻繁調用,String把這些被多次用到的重複代碼進行封裝,

  

  private final char value[];
  private int hash; // Default to 0
  private static final long serialVersionUID = -6849794470754667710L;
  private static final ObjectStreamField[] serialPersistentFields = new ObjectStreamField[0];
  首先是四個屬性,最後兩個是用來實現序列化和反序列化的,詳細內容會單獨講解
  第一個屬性:char value[]就表明了String字符串的本質,char數組表明它是引用類型,final表明它是常量,所以他是一個在JVM線程共享區的方法區中的常量,
所以每當我們創建一個String對象時,
都會在常量池中查找是否已經存在該常量,若存在就將該對象指向該常量,若不存在就先在常量池中創建該常量,然後再指向這個常量。
  這裏講一下常量和變量:可能有的同學對常量的概念很模糊,只知道常量和變量是相對的,
  變量:我們常說的局部變量和成員變量都是變量,變量分爲基本類型和引用類型,基本類型就是那八大類型(boolean,byte,char,short,int,long,float,double)而引用類型分爲三種,數組,類和接口
  常量:常量分爲倆種,字面值常量和自定義常量,比如說Math.min(2,3)其中的2和3就是直接傳入的倆個常量,在Math類中public static final double PI = 3.14159265358979323846這麼定義的PI就是自定義常量,
也就是我們通常意義上的常量,常量就是其值不可改變的,也就是用final修飾,比如說2就表示2,PI就表示3.14159265358979323846。static修飾詞限定了該常量的值被類的對象所共享,可以通過類名直接調用,Math.PI。
  第二個屬性hash,這個屬性會帶你走進hashCode()方法的神祕世界,詳情請參照hashCode()方法,這個hash屬性是用來在一定程度上標識字符串唯一性的,你可以把它認爲成一種ID,String類中hash並不是地址值,詳細去看一下hash表的數據結構,
這個hash只能稱之爲哈希碼。對於任意的一個類若不重寫hashCode方法,那返回的就是該對象的內存地址,重寫後返回的就是哈希碼。
  private static void checkBounds(byte[] bytes, int offset, int length)
  在String構造函數中用於檢查邊界,也就是檢查傳入的offset和length是否有問題
String(char[] value, boolean share)
  打包私有構造函數,它爲speed.this構造函數共享值數組,總是需要使用share == true來調用。需要單獨的構造函數,因爲我們已經有一個公共String(char [])構造函數,它可以複製給定的char[]。
不要糾結與這個Boolean類型的參數,它只是一個用來區別於String(char[])構造器的
  private boolean nonSyncContentEquals(AbstractStringBuilder sb)
  private static class CaseInsensitiveComparator implements Comparator<String>, java.io.Serializable {}
  
局部內部類,是String實現不區分大小寫的equals方法的核心代碼實現,詳情在public boolean equalsIgnoreCase(String anotherString)中
  private int indexOfSupplementary(int ch, int fromIndex)
  private int lastIndexOfSupplementary(int ch, int fromIndex)
  static int indexOf(char[] source, int sourceOffset, int sourceCount,String target, int fromIndex)
  static int indexOf(char[] source, int sourceOffset, int sourceCount,char[] target, int targetOffset, int targetCount,int fromIndex)
  static int lastIndexOf(char[] source, int sourceOffset, int sourceCount,String target, int fromIndex)
  static int lastIndexOf(char[] source, int sourceOffset, int sourceCount,char[] target, int targetOffset, int targetCount,int fromIndex)

 構造性函數:

  String的構造函數,還是很讓人懵逼的,總的來說他們的具體功能是就是將String ,char[],byte[],StringBuilder StringBuffer 轉換爲String類型,後幾個大家都容易理解,就是將其他類型裝換爲String類型,但是第一個呢,將String轉換爲String?這有什麼用呢?且聽我細細道來

我們先看源代碼(由於我之前在String源碼解析中已經發過了,這裏就不重複發了),new String()只有一行this.value = "".value;,new String(String original)只有兩行this.value = original.value;this.hash = original.hash;很簡單的吧

  這就引出了一道經典的面試題:String s = new String("gollong")創建了幾個對象?

    首先你要明白什麼創建對象,String s;並沒有創建對象,只是聲明一個引用,new String("gollong")纔是真正的創建對象,然後String s = new String("gollong")完成引用的實例化。

    其實你要明白這是調用的一個構造函數,傳入的參數是String類型的,那麼就很簡單了,我們將這一行代碼分解爲如下兩行

      String temp = "gollong";

      String s = new String(temp);

    這就好理解了吧,首先會在常量池中創建一個“gollong”,這是第一個對象(當然是在常量池中本身沒有這個對象的前提下),其次會在堆中創建第二個對象,因爲new出來的對象肯定及一定在堆中,再把前一個對象當做實參傳入到其中

    我用一張概念圖來解釋這個問題:

 

 

    public String()
    public String(String original)
    public String(char value[])
    public String(char value[], int offset, int count)
    public String(int[] codePoints, int offset, int count)
  看上去好像是將int數組轉換爲String,但是你去試試,輸出的東西並不是簡單的把每一個int值鏈接起來,這裏面大有學問,我們都知道java是採用Unicode字符集的,那Unicode內是怎麼表示的呢,
Unicode內部一共有三種長度的字符,分別佔用一個字節、兩個字節、四個字節,而這個int類型的數組就是指符合Unicode的四個字節長度的字符,在編碼一章中再講吧,太複雜了 @Deprecated
public String(byte ascii[], int hibyte, int offset, int count) public String(byte ascii[], int hibyte)
  已經過時的倆個方法,其意義是將byte數組轉換爲String對象,我們都知道byte類型只佔用一個字節,而組成String的char類型卻佔有兩個字節,這就涉及到互相轉換時高8位的處理問題了
而對於不同的編碼方式(請注意:在不詳細區別編碼和解碼是,編碼就是指編碼和解碼的統稱),處理方式是不同的,所以這兩個構造器可以讓使用者指定高8位的內容,但是人爲指定的往往是不正確的
所以標註爲過時(請注意:過時並不意味着不能用,只是不推薦使用,因爲它總有一 天會被淘汰的),纔有了以下的六個指定編碼方式的方法。
  
public String(byte bytes[], int offset, int length, String charsetName)throws UnsupportedEncodingException public String(byte bytes[], int offset, int length, Charset charset) public String(byte bytes[], String charsetName)throws UnsupportedEncodingException public String(byte bytes[], Charset charset) public String(byte bytes[], int offset, int length) public String(byte bytes[])
  指定編碼方式的將byte轉換爲char,其中可以通過兩個方式指定,一種是傳入編碼的字符串表示,最經常使用的方法,另一種是傳入Charset對象,畢竟能不造對象就不造,浪費空間
public String(StringBuffer buffer) public String(StringBuilder builder)

 轉換性函數:

  就是一些負責把其他類型的變量轉換爲String類型,或者把String轉換爲byte[],char[]

    public static String format(String format, Object... args)
    public static String format(Locale l, String format, Object... args)
    public static String join(CharSequence delimiter, CharSequence... elements)
    public static String join(CharSequence delimiter,Iterable<? extends CharSequence> elements)
  
public static String valueOf(Object obj) public static String valueOf(char data[]) public static String valueOf(char data[], int offset, int count)
  上面倆個內部調用的就是String的構造器new String(char data[])和new String(char data[],int offset,int count)
public static String copyValueOf(char data[], int offset, int count) public static String copyValueOf(char data[]) public static String valueOf(boolean b) public static String valueOf(char c) public static String valueOf(int i) public static String valueOf(long l) public static String valueOf(float f) public static String valueOf(double d)
  static修飾的類函數,可通過String.直接調用,返回一個String,類似於工具類的做法, 經常被用來將單個的各種類型轉換爲String,其實內部調用的就是八大數據類型的包裝類的toString方法
public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) public void getBytes(int srcBegin, int srcEnd, byte dst[], int dstBegin) public byte[] getBytes(String charsetName)throws UnsupportedEncodingException public byte[] getBytes(Charset charset) public byte[] getBytes() public char[] toCharArray()

 

 功能性函數:

  由於功能性函數很多,我把他們進行了詳細的分類

來自於Object的函數:

  繼承自Object類的三個方法,都很重要

  • equals :重寫後用來比較倆個字符串的每對應的倆個字符是否相等,也就是比較內容是否相等,很容易理解,但是往往與他同時出現的==就不是那麼容易理解了,在後面的第二部分中講解
  • hashCode:返回的是字符串額hash值,而在java中String的哈希碼計算規則是s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1],這裏就不列計算過程。’
  • toString:返回當前對象,並不是你想象當中的遍歷字符串中的每一個字符,而字符串對象直接輸出就是遍歷。根本不需要重寫toString方法,我相信你肯定聽說過這句話,輸出一個字符串對象就是輸出它的值,是因爲String重寫了toString方法,現在我說這句話是錯的你信嗎?
  public boolean equals(Object anObject)
  public int hashCode()
  public String toString()

判斷函數:

通過比較此字符串和指定的內容,返回一個boolean類型,一般用在if()和while()語句中,都是很常用的方法

  public boolean isEmpty()
  判斷字符串是否爲空,也及時判斷char數組的長度是否爲0   
public boolean contentEquals(StringBuffer sb)
  public boolean contentEquals(CharSequence cs)
  判斷內容是否相等,StringBuffer是什麼我們都知道,
CharSequence 是個什麼呢?其實CharSequence 是字符序列接口,我們所接觸到的像String,StringBuffer,StringBuider等都是它的實現類。大家既然都是字符串,哪來比較下內容也無可厚非嘛
  public boolean equalsIgnoreCase(String anotherString)  
  忽略大小寫的比較,核心調用的是regionMatches方法,而regionMathes是用來測試倆個字符串某些部分是否相等,而equals只能整個比較,這就是我們用它的原來,但是一般不怎麼使用,都是用contains
  public
boolean regionMatches(int toffset, String other, int ooffset,int len)
  public boolean regionMatches(boolean ignoreCase, int toffset,String other, int ooffset, int len)
  判斷字符串是否以指定字符串開始或結尾
  public boolean startsWith(String prefix, int toffset)   
  public boolean startsWith(String prefix)   
  public
boolean endsWith(String suffix)
 
  判斷字符串是否匹配指定的正則表達式
  public
boolean matches(String regex)  
  
判斷字符串是否包含指定的字符序列,注意傳入的是CharSequence對象
  public
boolean contains(CharSequence s)

 

比較函數:

比較函數其實也是判斷函數,只不過下面的三個函數返回值不是boolean類型的,我將他們單獨羅列出來,其實我們一般不會手動調用這些函數的,數組工具類Arrays中有一個方法排序方法sort()

public static void sort(Object[] a):這是不指定排序方式(元素之間怎麼比較)的方法,其實內部就是調用自然排序,也就是實現comparable接口實現的comparTo方法

public static <T> void sort(T[] a, Comparator<? super T> c):這是指定外部比較器的方法,這個比較器就是新建一個類實現Comparator接口重寫compare方法的比較方式,要比較的類型當做泛型傳遞進去,

在String類中,寫了一個成員內部類來實現這個比較器,在重寫compare方法,得到的功能是忽略大小寫的比較,在public int compareToIgnoreCase(String str)方法內得到體現,其實這個方法和public boolean equalsIgnoreCase(String anotherString)功能是一樣的

 

    public int compareTo(String anotherString)
    public static final Comparator<String> CASE_INSENSITIVE_ORDER = new CaseInsensitiveComparator();    
    public int compareToIgnoreCase(String str)

 

查詢函數:

  很常用的一些函數,具體作用是查詢某個字符或字符串的位置

    public int length()
   返回字符串的長度,也就是value的長度
public char charAt(int index)
   返回字符串中某個下標對應的字符,很實用的方法
public int codePointAt(int index)
   還記得codePoint是什麼嗎?他爲什麼是int類型的呢?去上面看看就明白了。返回對應下標的Unicode codePoint
public int codePointBefore(int index)
   返回對應下標前一個的Unicode codePoint
public int codePointCount(int beginIndex, int endIndex)
   返回指定範圍內Unicode codePoint的總數
public int offsetByCodePoints(int index, int codePointOffset)
   返回此 String 中從給定的 index 處偏移 codePointOffset 個代碼點的索引
public int indexOf(int ch) public int indexOf(int ch, int fromIndex) public int lastIndexOf(int ch) public int lastIndexOf(int ch, int fromIndex) public int indexOf(String str) public int indexOf(String str, int fromIndex) public int lastIndexOf(String str) public int lastIndexOf(String str, int fromIndex) public int indexOf(int ch) public int indexOf(int ch, int fromIndex) public int lastIndexOf(int ch) public int lastIndexOf(int ch, int fromIndex) public int indexOf(String str) public int indexOf(String str, int fromIndex) public int lastIndexOf(String str) public int lastIndexOf(String str, int fromIndex)
  上面的indexOf方法都是返回指定字符或者字符串第一次出現的下標,lastIndexOf是返回指定字符或者字符串的最後一次出現的下標,fromIndex用於指定開始的位置,這裏需要注意一點:
    從我們的習慣出發,肯定是自左向右搜索,indexOf方法便是這樣自左向右,fromIndex參數用於指定開始搜索的位置
    而lastIndexOf卻是自右向左搜索,找到的第一個便是我們要尋找的最後一個字符或字符串,所以fromIndex是指定開始搜索的位置,實際上就是我們習慣自左向右搜索方式的結束位置

功能函數:

  平時我們獲得字符串可以不是很滿意,需要我們通過一些函數去掉裏面的某些字符或者替換一些,再或者進行大小寫轉換,沒錯,下面的函數你都會用到。

    public String substring(int beginIndex)
    public String substring(int beginIndex, int endIndex)
  切片函數,說實話我學java到現在,不知道怎麼叫這個函數,只時稱呼他substring,這幾天在看python,python裏面是切片函數,聽起來還不錯就借用啦,哈哈,顧名思義,用一個字符串切出你想要的部分,說實話java中的切片函數遠沒有python中的好用,大家去看看python的就明白了
public CharSequence subSequence(int beginIndex, int endIndex)
  也是切片,返回的是CharSequence接口對象,說實話返回的就是一個String對象(自己去看源碼就知道了),其實就是一個向上轉型(CharSequence s = new String())。
public String concat(String str)
  類似於StringBUffer中的append函數,在字符串的結尾追加字符串,其內部調用的就是String(char[] ,boolean)構造器的,但是這種字符串追加的代價高昂,所以我們一般選擇StringBuffer和StringBuilder
public String replace(char oldChar, char newChar) public String replaceFirst(String regex, String replacement) public String replaceAll(String regex, String replacement) public String replace(CharSequence target, CharSequence replacement)
  以上四個是替換函數,其中第一個只能替換字符串中的所有的指定字符,注意只能替換單個字符
而第四個函數重構此方法後參數就變爲了CharSequence接口,現在對CharSequence很熟悉了吧,所以replace其實什麼都可替換,只不過一般我們都是操作字符串String,所以經常使用的是第三個。而第二個僅僅替換找到的第一個指定字符串
  public String[] split(String regex, int limit)   public String[] split(String regex)
  切割函數,根據指定的正則表達式切割字符串,返回結果是String數組,其中參數limit用於現代最終字符串數組的長度,前面都講過了,不進行詳細的講解了
  public String toLowerCase(Locale locale)   public String toLowerCase()   public String toUpperCase(Locale locale)   public String toUpperCase()
  將字符串中的字符全部轉換爲大寫或者小寫,其中locale用於指定本地規則
  public String trim()
  去除字符串兩端的空格,很實用的小函數
  public native String intern();

最後一個函數intern很有意思,作爲一個native方法,很底層,但是我們依然可以通過一個例子來揭開它神祕的面紗,我們明天實戰練習見!!!

寫了一天,可能有些字打錯了,或有些沒講清楚,望大家見諒☆ ̄(>。☆)。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章