[十二]基礎數據類型之String

在正式介紹String以前,咱們先介紹下CharSequencephp

char + sequence 就是字符的序列的意思css

Java中萬事萬物都是對象類型vue

而對於字符的序列,也就是多個char, 這麼一種東西, 使用CharSequence這個接口來描述ios

既然是接口,天然規定了做爲字符序列的基本協議c++

CharSequence簡介


char charAt(int index); 返回指定索引的char
int length() 返回字符序列的長度
CharSequence subSequence(int start, int end) 返回子序列
String toString() 返回一個包含此序列中字符的字符串該字符串與此序列的順序相同
default IntStream chars() 返回此序列的int stream,每一個char零位擴展爲int
default IntStream codePoints() 返回此序列的代碼點的stream
 
咱們都知道1.8的一個亮點就是stream和lambda
default方法也是1.8新增的,默認實現
既然CharSequence表示了 字符序列這麼一個概念
顯然,String內部是char數組,就是一個char的序列
 

String簡介

String 類表明字符串
Java 程序中的全部字符串字面值(如 "abc" )都是String的實例
內部有一個char[] 

注意到 上面的final, 字符串是常量;它們的值在建立以後不能更改
String str = "abc";
等效於:
char data[] = {'a', 'b', 'c'};
String str = new String(data);
Java 語言提供對字符串串聯符號("+")以及將其餘對象轉換爲字符串的特殊支持
說白了就是+被重載過了,也提供了強大的將對象轉換爲字符串的能力
char是UTF-16中的代碼單元,因此字符序列就是代碼單元的序列
仍舊是一個char多是一個字符,也多是半個字符
String 類提供處理 Unicode 代碼點(即字符)和 Unicode 代碼單元(即 char 值)的方法
 

屬性CASE_INSENSITIVE_ORDER

這就是一個比較器
邏輯也很簡單,兩個String 按照字典順序進行比較,忽略大小寫的
以二者length小的那個做爲循環次數,進行循環
若是第一個相等比較第二個,依次類推,直到不同
若是全部的都相等,那麼就比較長度了 return n1 - n2
 

字符與字節數組

在繼續下去以前,再次簡單介紹下字符與字節數組的關係
字符到字節,是一個編碼的過程
字節到字符是一個解碼的過程
一樣的一個字符,在不一樣的字符集和編碼方式下,實際存儲的值,將是不一樣的
好比前面說的Unicode字符集,UTF8 和UTF16編碼後的數據是不一樣的
這個編碼後的數據,也就是字節  , 他們是不同的 
一樣的一個編碼值,在不一樣的字符集中,可能表明着不一樣的字符
因此字符與字節之間,必然有編碼參與其中
這個編碼環節是必然存在的,不然,你就沒辦法把字節與字符聯繫起來
一個字符能夠根據 字符集編碼 進行多種方式的編碼
一個字節數組也能夠根據 字符集編碼 進行多種方式的解碼

對於同一個字符,無論進行何種編碼,當他們按照當初編碼的方式進行解碼時,必然對應的仍是一樣的那個字符
 

操做系統的文件都是以字節序列的形式存儲的,因此任何一個文件都是有編碼的
好比你在txt文件中輸入了一個字符
這個字符 底層就會使用指定的編碼存儲到字節中
軟件自己又把這個編碼以字符的形式呈現出來
因此你纔看獲得是一個字符
好比這個文件中11111.txt中,存儲了一個漢字春天的 " 春" 
編碼方式是UTF8
二進制軟件查看是E6 98 A5
與咱們進行UTF8 編碼計算的結果是對應的
ANSI編碼
不一樣的國家和地區制定了不一樣的標準
由此產生了 GB23十二、GBK、Big五、Shift_JIS 等各自的編碼標準
這些使用 1 至 4 個字節來表明一個字符的各類漢字延伸編碼方式,稱爲 ANSI 編碼
在簡體中文Windows操做系統中,ANSI 編碼表明 GBK 編碼;
在日文Windows操做系統中,ANSI 編碼表明 Shift_JIS 編碼

再看下面一個例子
使用ultraedit 新建了一個文件,裏面寫了一個漢字 "春",
其實這個默認格式就是操做系統的編碼,也就是ANSI  也就是GBK
查看二進制編碼爲 B4 BA
而後咱們再去對照GBK的碼錶,你會發現徹底對的上
任何一個文件,他其實有自帶或者說默認的一個編碼
凡是呈現字符的地方,都有一個編碼在默默地支撐,纔可以讓你看得見,看得清楚字符
這個字符的保存 , 就是字符按照編碼表  編碼 成字節序列的過程
這個字符的呈現 , 就是字節序列按照編碼表  解碼 成字符的過程
當你使用計算機,進行字符處理工做的時候,無時無刻都在進行着編碼與解碼

String構造方法

String是經常使用類之一,因此提供了很是豐富的方法
String是字符序列  內部是char[]   char就是一個十六進制的數 16位表示
因此char[] 能夠用來構造String
char是16位數可以表示代碼單元, int天然能夠直接表示一個代碼點了,因此也可使用int來構造String
另外再加上咱們剛纔關於字節數組與字符關係的介紹,也可使用字節數組構造String
 
下面表格是幾個基本的構造方法
String() 空String ,沒啥必要由於String是不可變的

String(char[])
String(char[], int, int)
藉助於字符數組或者字符數組的一部分建立對象
內部原本就是字符數組 char[]  因此天然可使用char[]構造
直接進行拷貝,因此對原有字符數組的修改不影響String對象

String(int[], int, int) 使用代碼點構造String
public String(int[] codePoints, int offset, int count)
offset 和 count爲範圍限制
String(String)
String(StringBuffer)
String(StringBuilder)
 

getBytes 方法

先提一下另一個方法,getBytes
使用指定的字符集將此 String 編碼爲 byte 序列
個人編輯器環境是UTF8編碼的      
"春" 的UTF8編碼上面已經分析了
 
也就是說我這邊有一個UTF8的字符"春"  源文件中保存的是 E6 98 A5
對於下面全部的getBytes來講,"春" 這個字符形狀符號是不變的
得到的字節數組就是  這個字符形狀符號 根據不一樣字符集編碼方式, 編碼而獲得的字節數組
下面的各類轉換換一個描述就是:UTF8的字符"春" ,在其餘的字符集下面,編碼都是多少啊?
爲何UTF-8 是-26  -104 -91 ? 而不是e6 98 a5?進制問題
getBytes總共三種形式
指定編碼或者使用默認
getBytes(String)
getBytes(Charset)
getBytes()
還有一種已經棄用 了
 

經過字節數組 byte[] 構造

String提供了6個跟byte[]  相關的構造方法
 
getBytes方法是字符是固定的, 固定的以UTF8格式存儲在個人源文件中,
而後根據不一樣的編碼方式,轉換爲字節數組 byte[]
 
String的構造方法,則是將各個已經編碼過的字節數組 byte[] 按照指定的編碼方式解析 還原成爲一個字符
而後再將這個字符以char[]  也就是UTF-16的方式進行存儲的
個人源文件IDE環境是UTF8那麼最終構造的String就是UTF8的,不會是其餘的
 
好比下面的構造方法,使用前面示例中的 bytes數組
 
而後使用  String(byte[], String)   進行構造
看得很清楚
String字符串 s1 中存儲的value 是Unicode的代碼點U+6695    (0號平面,一個代碼單元就是一個代碼點)
也就是十進制的26149
 
使用byte[] 字節數組構造String的過程是下圖這樣子的
字節數組,根據指定字符編碼轉換爲那個字符
而後在把字符按照UTF16 進行編碼 存儲到String中的char[]
上面的例子能夠很好地印證這一點,字節數組是[-76, -70] 
也就是 :    ffffffb4   ffffffba   也就是 B4 BA 明明是GBK的"春"
根本就不是6625 對應關係就是他們表示的是同一個字符
既然字節數組與字符的轉換離不開編碼,因此天然經過byte[] 構造String對象時,必需要有編碼
不設定並非沒有,而是使用默認的
既然使用字節數組,那麼有的時候可能須要指定範圍,因此有兩個根本的構造方法
而後還有默認字符編碼的簡化形式
再而後就是長度爲整個字節數組的簡化形式
這幾個構造方法根本在於理解 字節數組與字符的轉換
以及必須的byte[] 字節數組  以及  編碼
 

valueOf

valueOf 系列用來包裝
String中用來將基本類型 以及 Object 轉換爲String
char相關的都是直接構造String對象
其他(除了boolean,他是轉換爲字符串  true和false返回)
都是toString
 

copyValueOf

copyValueOf方法內部就是直接調用的兩個構造方法
還不如直接使用new建立來的直接,只不過使用這個方法有更好的可讀性
 

獲取指定位置代碼單元和代碼點的方法

charAt(int) 
返回指定索引處的 char 值  索引範圍爲從 0 到 length() - 1
簡單粗暴,  無論三七二十一就是代碼單元  
若是是輔助平面,那就多是代理項
codePointAt(int)
返回指定索引處的代碼點,  範圍從 0 到 length() - 1
他跟Character中的codePointAt方法邏輯含義是同樣的
若是是高代理,若是下一個也在掌控範圍內,若是下一個是低代理,那麼返回代碼點
不然,返回代碼單元 也就是一個char
codePointBefore(int)
返回指定索引以前的字符(Unicode 代碼點)  其範圍從 1 到 length
他跟Character中的codePointBefore方法邏輯含義是同樣的
若是index-1 是低代理,若是在往前一個index-2 也是有效範圍內,若是他還剛好是一個高代理,返回代碼點
不然,返回代碼單元,也就是一個char
codePointCount(int, int)
此 String 的指定文本範圍中的 Unicode 代碼點數
文本範圍始於指定的 beginIndex,一直到索引 endIndex - 1 處的 char,  包含頭不包含尾
該文本範圍的長度(用 char 表示)是 endIndex-beginIndex
因爲一個代碼點的代碼單元個數多是1個多是2個,因此代碼點的個數須要計算,就不直觀了
他跟Character中的codePointCount方法邏輯含義是同樣的
offsetByCodePoints(int, int)
他跟Character中的offsetByCodePoints方法邏輯含義是同樣的
返回此 String 中從給定的 index 處偏移 codePointOffset 個代碼點的索引
根本緣由仍是一個代碼點的代碼單元個數多是1個多是2個 
因此 偏移codePointOffset個代碼點的 代碼單元的個數不肯定,須要調用方法計算
 

getChars(int, int, char[], int)複製

實例方法
就是一個複製方法,名字不太規範
複製String中指定索引開始的srcBegin 和 srcEnd   包含頭不包含尾
到另外一個字節數組 char dst[]中, 存放的起始位置爲dstBegin
public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin)

須要注意的是,複製的是char  代碼單元
就是String 內部char[] 的下標索引
 

開始結束匹配校驗

startsWith(String, int)
startsWith(String)
實例方法
測試String是否以指定的前綴開始
還能夠指定起始位置處開始比較

從源代碼看得出來,挨個比較內部的char
從頭開始,所有一致才返回true

單參數是雙參數的簡化版本
endsWith(String) endwith就是從最後的指定參數長度的位置開始比較
 

indexOf 和lastIndexOf

indexOf 和XXXIndexOf系列都是獲取下標索引相關
須要注意的是,他們的參數都是int或者String
也就是說這些方法都是真正的字符相關的
int indexOf(int ch)
int indexOf(int ch, int fromIndex)
返回   指定字符  在此字符串中第一次出現處的索引
返回的匹配的第一個

也能夠指定檢索的起始位置, 若是指定了索引
那麼返回的值將  大於等於  指定的索引

換個說法:
若是是0號平面返回的是那個代碼單元也就是代碼點的索引
charAt(k) == ch   爲 true 的最小 k 值  
若是是輔助平面返回的是高代理位的代碼單元的索引  
codePointAt(k) == ch  爲 true 的最小 k 值  
int indexOf(String str)
int indexOf(String str, int fromIndex)
返回  指定子字符串   在此字符串中第一次出現處的索引
返回匹配的第一個
 
也能夠指定檢索的起始位置,若是指定了索引
那麼返回值須要大於等於 指定的索引
 
匹配的含義爲startsWith(str) 爲true
若是指定檢索開始的位置,  那麼
不只僅startsWith(str) 爲true 還須要索引知足指定的下標範圍
不然仍舊是返回-1
lastIndexOf(int)
lastIndexOf(int, int)
返回指定字符在此字符串中最後一次出現處的索引
返回匹配的最後一個

也能夠指定檢索位置,可是這個檢索位置與indexOf不一樣
indexOf中指定的索引,是從索引處日後
lastIndexOf指定的索引, 是反向,從索引處往前
指定了索引就要求 返回值 小於等於 指定索引

換個說法
若是是0號平面返回的是那個代碼單元也就是代碼點的索引
charAt(k) == ch   爲 true 的最大 k 值 
若是是輔助平面返回的是高代理位的代碼單元的索引 
codePointAt(k) == ch  爲 true 的最大 k 值   而且  k 小於等於 指定的索引
lastIndexOf(String)
lastIndexOf(String, int)
返回指定 子字符串 在此字符串中最後一次出現處的索引
返回匹配的最後一個
 
也能夠指定檢索位置,檢索索引的位置也是反向搜索
 
匹配的含義爲startsWith(str) 爲true
指定了索引就要求返回值 小於等於  指定索引
 
總共三個維度
匹配第一個或者最後一個 / 匹配字符或者字符串 / 是否指定查找範圍 
8個方法
 
indexOf是從前日後匹配  匹配的是第一個 若是指定了下標索引,從索引處日後找  
返回的值要  大於等於 索引
 
lastIndexOf是從後往前匹配  匹配的是最後一個  若是指定了開始下表索引,是從索引處往前,反向查找
返回的值要  小於等於 索引
 
匹配字符若是是BMP,代碼單元就是代碼點,返回的就是那個代碼單元也是代碼點的索引
若是是輔助平面,一個代碼點兩個代碼單元,返回的就是高代理位的索引  lastIndexOf和indexOf都是返回高代理項
 

length 

長度獲取,內部char數組的長度
相關文章
相關標籤/搜索