String字串
說在前面的話:
String類是我個人認為是Java設計當中一個特殊的,雖然String本身特殊引用資料型別 但是她卻可以想基本資料型別那樣直接賦值!!!
1.String類的兩種物件例項化方式
String類之所以特殊,主要原因在於其有兩種不同的物件的例項化方式.
-
採用直接賦值字串的形式為String類物件例項化(推薦使用的寫法)
package com.shxt.demo01; public class StringDemo01 { public static void main(String[] args) { String str = "直接方式例項化方式";//使用頻率特別高 System.out.println(str); } } 複製程式碼
-
採用String類的構造方法為String類進行例項化,String類過載了構造方法,在Java EE中我們會使用到字串轉碼問題等會使用到
package com.shxt.demo01; public class StringDemo02 { public static void main(String[] args) { String str = new String("建構函式例項化String字串"); System.out.println(str); } } 複製程式碼
2.String是不可變的
對下面的程式碼進行分析說明
package com.shxt.demo01;
public class StringDemo03 {
public static void main(String[] args) {
String s = "abcd";
s = "dbcdel";
}
}
複製程式碼
String不可變很簡單,我們給一個已有的s字串變數賦值為"abcd",第二次賦值成"abcdel",不是在原記憶體地址上修改,而是重新執行一個新物件,行地址.
為什麼String就是不可變的呢? 我需要知道原因
開JDK原始碼,java.lang.String類起手前三行,是這樣寫的:
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/* String的本質是一個char陣列,並且使用了final關鍵修飾*/
/** The value is used for character storage. */
private final char value[];
... ...
... ...
}
複製程式碼
程式碼分析:
1.String類是用final關鍵字修飾,這說明String不可繼承
2.String類的主要成員欄位value是個char[ ]陣列,而且是用 final 修飾的。
final修飾的欄位建立以後就不可改變。
3.String類的用法說明
String類在java.lang包中,java使用String類建立一個字串變數,字串變數屬於物件。java把String類宣告的final類,不能有子類。String類物件建立後不能修改,由0或多個字元組成,包含在一對雙引號之間,下面簡單的熟悉一下其常用的API
java.lang.String
char charAt (int index) 返回index所指定的字元
String concat(String str) 將兩字串連線
boolean endsWith(String str) 測試字串是否以str結尾
boolean equals(Object obj) 比較兩物件
char[] getBytes 將字串轉換成字元陣列返回
char[] getBytes(String str) 將指定的字串轉成制服陣列返回
boolean startsWith(String str) 測試字串是否以str開始
int length() 返回字串的長度
String replace(char old ,char new) 將old用new替代
char[] toCharArray 將字串轉換成字元陣列
String toLowerCase() 將字串內的字元改寫成小寫
String toUpperCase() 將字串內的字元改寫成大寫
String valueOf(Boolean b) 將布林方法b的內容用字串表示
String valueOf(char ch) 將字元ch的內容用字串表示
String valueOf(int index) 將數字index的內容用字串表示
String valueOf(long l) 將長整數字l的內容用字串表示
String substring(int1,int2) 取出字串內第int1位置到int2的字串
複製程式碼
(1) 字串比較
A.字串上使用"=="比較
實際開發中字元的比較不會使用"=="進行比較,請回顧我們之前學習的記憶體地址方面的知識
package com.shxt.demo01;
public class StringDemo04 {
public static void main(String[] args) {
String str1 = "hanpang" ; //直接賦值例項化物件
String str2 = new String("hanpang"); //構造方法例項化物件
String str3 = str2; //引用傳遞
System.out.println(str1==str2); // false
System.out.println(str1==str3); // false
System.out.println(str2==str3); // true
}
}
複製程式碼
記憶體分析圖如下:
程式碼分析:
使用"=="的確完成了相等的判斷,但是最終判斷的是兩個物件是否相等,屬於數值判斷--判斷兩個物件的記憶體地址的數值,並沒有判斷起內容
如果想完成字串內從的判斷,必須要使用String類的操作方法
public boolean equals(String str) 複製程式碼
B.使用equals()方法進行比較
package com.shxt.demo01;
public class StringDemo05 {
public static void main(String[] args) {
String str1 = "hanpang" ; //直接賦值例項化物件
String str2 = new String("hanpang"); //構造方法例項化物件
String str3 = str2; //引用傳遞
System.out.println(str1.equals(str2)); //true
System.out.println(str1.equals(str3)); //true
System.out.println(str2.equals(str3)); //true
}
}
複製程式碼
C.使用equals()方法的陷阱
以後要注意如何使用equals方法
package com.shxt.demo01;
public class StringDemo06 {
public static void main(String[] args) {
String str1 = null ;
if(str1.equals("Hello")){
System.out.println("成功");
}
}
}
複製程式碼
執行後會在控制檯報空指標的異常資訊
Exception in thread "main" java.lang.NullPointerException
at com.shxt.demo01.StringDemo06.main(StringDemo06.java:6) //錯誤的位置
複製程式碼
修改後的程式碼為[重點!重點!重點]
package com.shxt.demo01;
public class StringDemo06 {
public static void main(String[] args) {
String str1 = null ;
if("Hello".equals(str1)){ //修改後的程式碼
System.out.println("成功");
}
}
}
複製程式碼
常見面試題分析,請解釋String類中"=="和"equals()"的區別?
- == : 比較兩個字串記憶體地址的數值是否相等,屬於數值比較
- equals() : 比較兩個字串的內容,屬於內容比較
簡單的面試,這個屬於常識
(2) 字串與字元
編號 | 方法名稱 | 型別 | 描述 |
---|---|---|---|
1 | public String(char[] value) | 構造方法 | 將字元陣列內容變成字串 |
2 | public String(char[] value,int offset,int count) | 構造方法 | 將部分字元陣列變為字串 offset表示開始點 count標識操作的長度 |
3 | public char charAt(int index) | 普通方法 | 取得指定索引位置的字串, 索引從0開始 |
4 | public char[] toCharArray() | 普通方法 | 將字串轉換為字元陣列 |
驗證charAt()方法
package com.shxt.demo01;
public class StringDemo07 {
public static void main(String[] args) {
String str = "welcomeshxt" ;
char c = str.charAt(0);
System.out.println(c);
}
}
複製程式碼
驗證toCharArray()方法
package com.shxt.demo01;
public class StringDemo08 {
public static void main(String[] args) {
String str = "welcomeshxt" ;
char[] data = str.toCharArray();
for (int i = 0; i < data.length; i++) {
System.out.print(data[i]+",");
}
}
}
複製程式碼
練習題
將全小寫的英文字串"welcomeshxt",變成大寫的字串,在控制檯輸出的內容為WELCOMESHXT 和 SHXT 兩個字串
package com.shxt.demo01;
public class StringDemo09 {
public static void main(String[] args) {
String str = "welcomeshxt" ;
}
}
複製程式碼
(4) 字串和位元組
編號 | 方法名稱 | 型別 | 描述 |
---|---|---|---|
1 | public String(byte[] bytes) | 構造方法 | 將位元組陣列內容變成字串 |
2 | public String(byte[] bytes,int offset,int length) | 構造方法 | 將部分位元組陣列變為字串 |
3 | public byte[] getBytes() | 普通方法 | 將字串變為位元組陣列 |
4 | public byte[] getBytes(String charsetName) throws UnsupportedEncodingException |
普通方法 | 字串轉碼操作[重點] |
package com.shxt.demo01;
public class StringDemo09 {
public static void main(String[] args) {
String str = "welcomeshxt" ;
byte[] data = str.getBytes();
for (int i = 0; i < data.length; i++) {
System.out.print(data[i]+",");
data[i] -=32;//擴充套件賦值運算子,不會改變型別
}
System.out.println();
System.out.println("全部位元組轉為字串:"+new String(data));
System.out.println("全部部分位元組轉為字串:"+new String(data,7,4));
}
}
複製程式碼
(5) 字串查詢
在String類中提供了從一個字串查詢指定字串是否存在的操作,下面提供的說明必須要牢記
編號 | 方法名稱 | 型別 | 描述 |
---|---|---|---|
1 | public boolean contains(String s) | 普通方法 | 查詢指定的字串是否存在 |
2 | public int indexOf(String s) | 普通方法 | 從頭查詢指定的字串位置, 找不到返回-1 |
3 | public int indexOf(String s,int fromIndex) | 普通方法 | 由指定位置向後查詢字串的位置, 找不到返回-1 |
4 | public int lastIndexOf(String s) | 普通方法 | 從後查詢指定的字串位置, 找不到返回-1 |
5 | public int lastIndexOf(String s,int fromIndex) | 普通方法 | 從指定的位置由後向前查詢 |
6 | public boolean startsWith(String prefix) | 普通方法 | 判斷是否以指定的字串開頭 |
7 | public boolean startsWith(String prefix,int offset) | 普通方法 | 從指定的位置判斷是否以指定的字串開頭 |
8 | public boolean endsWith(String suffix) | 普通方法 | 判斷是否以指定字串結尾 |
package com.shxt.demo01;
public class StringDemo10 {
public static void main(String[] args) {
String str = "##pang@@sir**" ; //定義一個字串
System.out.println(str.startsWith("##")); //判斷開頭
System.out.println(str.startsWith("sir",5)); // 從指定的位置開始判斷開頭
System.out.println(str.endsWith("**")); // 判斷結尾
System.out.println(str.contains("sir")); //查詢字串是否存在
System.out.println(str.contains("AA"));
System.out.println(str.indexOf("sir"));//查詢字串的位置
System.out.println(str.indexOf("AA"));
System.out.println(str.lastIndexOf("sir"));//查詢字串的位置
System.out.println(str.lastIndexOf("AA"));
}
}
複製程式碼
(6) 字串擷取
編號 | 方法名稱 | 型別 | 描述 |
---|---|---|---|
1 | public String substring(int beginIndex) | 普通方法 | 從指定位置擷取到結尾 |
2 | public String substring(int beginIndex,int endIndex) | 普通方法 | 擷取部分字串 |
package com.shxt.demo01;
public class StringDemo12 {
public static void main(String[] args) {
String str = "Hello World" ;
System.out.println(str.substring(2));
System.out.println(str.substring(2,8)); // [2,8)
}
}
複製程式碼
練習題
- 已知一個檔名稱為"西遊記.悟空.docx"的字串,請獲取該檔案的字尾名稱 docx
(7) 字串替換操作
編號 | 方法名稱 | 型別 | 描述 |
---|---|---|---|
1 | public String replace(char oldChar,char newChar) | 普通方法 | 字元替換,不常用 |
2 | public String replaceAll(String regex,String s) | 普通方法 | 全部替換 |
3 | public String replaceFirst(String regex,String s) | 普通方法 | 替換首個 |
package com.shxt.demo01;
public class StringDemo11 {
public static void main(String[] args) {
String str = "pangpang" ;
System.out.println(str.replace('n','X'));
System.out.println(str.replaceAll("an","*"));
System.out.println(str.replaceFirst("an","#"));
}
}
/**
執行結果
paXgpaXg
p*gp*g
p#gpang
*/
複製程式碼
(8) 字串拆分
編號 | 方法名稱 | 型別 | 描述 |
---|---|---|---|
1 | public String[] split(String regx) | 普通方法 | 按照指定的字串全拆分 |
2 | public String[] split(String regx,int limit) | 普通方法 | 拆分為指定的長度 |
package com.shxt.demo01;
public class StringDemo13 {
public static void main(String[] args) {
String str = "Hello#World#!!!" ;
String[] result = str.split("#");
for (int i = 0; i < result.length; i++) {
System.out.println(result[i]);
}
}
}
複製程式碼
練習題:(進行拆分時也會出翔一些字元無法進行拆分,此時需要使用\\(表示一個\)
)進行轉義
- 拆分IP地址(192.168.7.199),輸出結果為 192 168 7 199
(9) 其他方法
編號 | 方法名稱 | 型別 | 描述 |
---|---|---|---|
1 | public boolean isEmpty() | 普通方法 | 判斷是否為空的字串("") 無法進行null的判斷 |
2 | public int length() | 普通方法 | 取得字串長度 |
3 | public String trim() | 普通方法 | 去掉左右空格 |
4 | public String toLowerCase() | 普通方法 | 將全部字母轉小寫 |
5 | public String toUpperCase() | 普通方法 | 將全部字母轉大寫 |
6 | public String concat(String s) | 普通方法 | 字串連線(+) |
package com.shxt.demo01;
public class StringDemo14 {
public static void main(String[] args) {
String str = "Hello World" ;
System.out.println(str.isEmpty());//false
System.out.println("".isEmpty());//true
System.out.println(str.length());//獲取長度
System.out.println(" HAHA ".length());
System.out.println(" HAHA ".trim().length());//去空格的長度
System.out.println(str.toLowerCase());
System.out.println(str.toUpperCase());
System.out.println(str.concat("HAHA").concat("WOWO"));
}
}
複製程式碼
練習題
- 設定字串的首字母大寫
user_name
→User_name
(10) 字串與基本資料型別互轉
A.基本資料型別轉字串
String類中提供了String valueOf()放法,用作基本型別轉換為字串型別
static String valueOf(char data[])
static String valueOf(char data[], int offset, int count)
static String valueOf(boolean b)
static String valueOf(char c)
static String valueOf(int i)
static String valueOf(long l)
static String valueOf(float f)
static String valueOf(double d)
複製程式碼
package com.shxt.demo01;
public class StringDemo15 {
public static void main(String[] args) {
int num = 100;
String s1 = String.valueOf(num);
String s2 = ""+100;
}
}
複製程式碼
B.字串轉基本資料型別
java.lang包中有Byte、Short、Integer、Float、Double類的呼叫方法:
public static byte parseByte(String s)
public static short parseShort(String s)
public static short parseInt(String s)
public static long parseLong(String s)
public static float parseFloat(String s)
public static double parseDouble(String s)
複製程式碼
package com.shxt.demo01;
public class StringDemo16 {
public static void main(String[] args) {
String s = "999";
int num1 = Integer.parseInt(s);
long num2 = Long.parseLong(s);
float num3 = Float.parseFloat(s);
System.out.println(num1+"-"+num2+"-"+num3);
}
}
複製程式碼
StringBuffer和StringBuilder
我們來分析一下字串的程式程式碼,看看這段程式碼為什麼要在實際開發中儘量避免呢?
package com.shxt.demo02;
public class Demo01 {
public static void main(String[] args) {
String str = "";
for (int i = 0; i < 10000; i++) {
str += i; //字串拼接
}
System.out.println(str);
}
}
複製程式碼
程式碼分析:
我們說過String是不可變的,上面的程式碼需要"斷開-連線"String物件10000次,會產生大量垃圾,所以不推薦這種方式,那麼我們如何改進程式碼呢?
1.StringBuffer類
StringBuffer字串變數(執行緒安全)是一個容器,最終會通過toString方法變成字串;
public final class StringBuffer
extends AbstractStringBuilder
implements java.io.Serializable, Appendable, CharSequence
{
/**
* Constructs a string buffer with no characters in it and an
* initial capacity of 16 characters.
*/
public StringBuffer() {
super(16);
}
public synchronized StringBuffer append(int i) {
super.append(i);
return this;
}
public synchronized StringBuffer delete(int start, int end) {
super.delete(start, end);
return this;
}
}
複製程式碼
程式碼分析:
super(16)呼叫AbstractStringBuilder的抽象類的建構函式,對字元陣列進行初識化操作
abstract class AbstractStringBuilder implements Appendable, CharSequence { char[] value; AbstractStringBuilder(int capacity) { value = new char[capacity]; } } 複製程式碼
我們發現字元陣列不是final修飾,意味著是可變的!
A.StringBuffer的內容是可以改變的,引用傳遞
package com.shxt.demo02;
public class Demo02 {
public static void main(String[] args) {
StringBuffer buf = new StringBuffer(); //定義StringBuffer物件
buf.append("Han ").append(" Pang"); //連線字串
fun(buf); //引用傳遞
System.out.println(buf.toString()); //將buf轉為字串
}
public static void fun(StringBuffer temp){
temp.append(" Welcome ").append("shxt");
}
}
複製程式碼
編號 | 方法名稱 | 型別 | 描述 |
---|---|---|---|
1 | public StringBuffer append(資料型別 b) | 普通方法 | 追加內容到當前StringBuffer物件的末尾, 類似於字串的連線。 呼叫該方法以後, StringBuffer物件的內容也發生改變 |
2 | public StringBuffer deleteCharAt(int index) | 普通方法 | 刪除指定位置的字元, 然後將剩餘的內容形成新的字串 |
3 | public StringBuffer insert(int offset, 資料型別 b) | 普通方法 | 插入內容,然後形成新的字串 |
4 | public StringBuffer reverse() | 普通方法 | 內容反轉 |
5 | public void setCharAt(int index, char ch) | 普通方法 | 修改物件中索引值為index位置的字元為新的字元ch |
6 | public void trimToSize() | 普通方法 | 將StringBuffer物件的中儲存空間縮小到和 字串長度一樣的長度,減少空間的浪費 |
package com.shxt.demo02;
public class Demo03 {
public static void main(String[] args) {
StringBuffer buf = new StringBuffer("西遊記"); //定義StringBuffer物件,並初始化資料
buf.append(",悟空").append(999); //append追加內容
System.out.println("結果1"+buf.toString());
//刪除資料
buf = buf.deleteCharAt(buf.length()-1);
buf = buf.deleteCharAt(buf.length()-1);
buf = buf.deleteCharAt(buf.length()-1);
System.out.println("刪除後的結果:"+buf.toString());
//插入資料
buf.insert(3,"====>");
System.out.println("插入後的結果:"+buf.toString());
buf.replace(3,8,"");//替換資料
System.out.println("替換後的結果:"+buf.toString());
//反轉資料
buf.reverse();
System.out.println("反轉的資料為:"+buf.toString());
}
}
/*
結果1西遊記,悟空999
刪除後的結果:西遊記,悟空
插入後的結果:西遊記====>,悟空
替換後的結果:西遊記,悟空
反轉的資料為:空悟,記遊西
*/
複製程式碼
StringBuffer sb=new StringBuffer();
sb.delete(0, sb.length());
sb.setLength(0);
StringBuffer通過使用sb.setLength(0)來清空StringBuffer物件中的內容效率最高
2.StringBuilder類
StringBuilder 字串變數(非執行緒安全),使用方式跟StringBuffer一樣
3.區別
String
繼承於CharSequence
,也就是說String
也是CharSequence
型別StringBuilder
和StringBuffer
都是可變的字元序列。它們都繼承於AbstractStringBuilder
,實現了CharSequence
介面String
是不可變的,StringBuffer
、StringBuilder
是可變的StringBuilder
是非執行緒安全的,而String
(不可變物件)、StringBuffer
(對方法加了同步鎖或者對呼叫的方法加了同步鎖)是執行緒安全的StringBuilder
適用於單執行緒環境,StringBuffer
適用於多個執行緒操作同一個字串- 大部分情況下:
StringBuilder
>StringBuffer
>String
參考資料: https://juejin.im/entry/59082ab5a0bb9f006510683a