關於String的一些實用技能
一、String
面試經常會看到關於String,到底String是怎麼一回事呢 ?
- String的常量池
JVM在堆中開闢了一段空間迎來緩存所有使用字面量
創建的字符串對象,只要發現已經創建過的字符串
字面量創建新字符串時,JVM會直接使用緩存的對象
而不是在創建新對象,這樣做避免內存堆積大量
內容一樣的字符串對象,降低內存開銷
一、
//直接量 字面量
String s1 = "123abc";
String s2 = "123abc";//重用S1創建的對象
String s3 = "123abc";//一樣重用
System.out.println(s1==s2);//true
System.out.println(s1==s3);//true
上邊爲什麼會是true?
s1、s2、s3 三個裏面內容是相同的;s3會利用之前(s1)的緩存123abc 。( s2同理 )
所以爲true。
二、
String s1 = "123abc";
String s2 = "123abc";
//一旦修改內容,就會創建新對象
s1 = s1+"!";//s1不在指向原對象
System.out.println("s1:"+s1);//123abc!
System.out.println("s2:"+s2);//123abc
這個時候s1輸出爲 123abc!,會不在指向原對象。
三、
String s2 = "123abc";
//new是一個比較強制的操作,一定創建新對象
String s4 = new String("123abc");
System.out.println("s4:"+s4);
System.out.println(s2==s4);//false
這次會輸出false,因爲new是一個比較強制的操作,一定創建個對象。
雖然內容相同,但是兩者對象不同,所以比較爲false!
四、
/**
* 這裏觸發了編譯器一個特點
* 編譯器在編譯代碼時若出現一個表達式
* 參與的值都是字面量時,那麼該計算表達式的結果
* 是確定的,此時編譯器計算表達式的結果,將結果替換表達式
* 這樣一來JVM每次執行字節碼文件就不用計算了
* 下面的代碼會被編譯器編譯後爲:
* String s5="123abc";
*/
String s5 = "123"+"abc";
String s2 = "123abc";
System.out.println("s5:"+s5);
System.out.println(s2==s5);//true
上邊說到了,編譯器的特點。雖然兩者是相加的,但表達式參與值爲字面量,直接把結果確定;
兩者對象比較,值相同,所以爲false
五、
String s = "123";
String s6 = s+"abc";
System.out.println(s2==s6);//false
上邊說到了,當使用了字面量時,會自動變爲結果進行比較。
當使用了一個變量,不是字面量時。進行比較對象,爲false!
二、String不適合頻繁修改
字符串是不變對象,若想改變內容一定會創建新對象
這樣的做法源自JVM對字符串的優化,但是這樣的做法
弊端修改字符串時性能低下(雖然這樣的操作不頻繁)
頻繁修改產生大量垃圾,內存開銷大,運行效率差
結論:String不適合頻繁修改
三、String、StringBuffer、StringBuilder區別
StringBuffer與StringBuilder相同點都是字符串變量,是可改變的對象,每當我們用它們對字符串做操作時,
實際上是在一個對象上操作的。String每次操作會創建一些新的對象,所以速度快些。
不同點是StringBuilder是線程非安全的,StringBuffer是線程安全的, 當我們在字符串緩衝區被多個線程使用時,
JVM不能保證StringBuilder的操作是安全的,雖然它的速度最快,但是可以保證StringBuffer是可以正確操作的。
當然大多數情況下我們是在單線程下進行的操作,所以大多數情況下建議使用StringBuilder而不用StringBuffer的,
就是速度的原因。
對於三者使用的總結:
1.如果要操作少量的數據使用 String。
2.單線程操作字符串緩衝區,操作大量數據使用 StringBuilder。
3.多線程操作字符串緩衝區,操作大量數據使用 StringBuffer。
--------------------------------------------------------
String的使用
1、 char charAt(int index)
-
下標 獲取當前字符串中指定位置對應的字符
String str="thinking in java"; char c=str.charAt(9); System.out.println(c);//i
注意:第一個是從0開始數的。
這時會輸出String str變量中的第九個下標對應的。
2、int indexOf(String str)
-
檢定給定的當前字符串中的位置
-
若當前字符串不包含給定內容,則返回值爲-1
String str="thinking in java"; //查找str中"in"所在的位置 int index = str.indexOf("in");//2 System.out.println(index); //從指定位置開始查找第一次出現"in"的位置 index = str.indexOf("in",3); System.out.println(index);//5 //查找最後一次出現"in"位置 index = str.lastIndexOf("in"); System.out.println(index);//9
3、int length()
-
獲取當前字符串長度(字符個數)
String str = "我愛java!!"; int length = str.length(); System.out.println("len:"+length);//len:8
4、boolean startsEith(String str)
boolean endsWith(String str)
-
判斷一個字符串是否以字符開始或結尾的
String str="thinking in java"; boolean starts =str.startsWith("thi"); System.out.println("start:"+starts);//true boolean ends =str.endsWith("ava"); System.out.println("ends:"+ends);//true
5、String substring(int start,int end)
-
截取指定範圍內的字符串,兩個參數分別表示下標
-
從start處開始,end結束(不包含end處的字符)
-
java API中的參數有一個特點,通常用兩個數字表示
-
範圍時都是“含頭不含尾”的。
String str="eee.hhhh.com"; String sub=str.substring(4,8); System.out.println(sub);//hhhh //從指定位置開始截取到字符串末尾 sub=str.substring(4); System.out.println(sub);//hhhh.com
6、String toUpperCase()
String toLowerCase()
-
將當前英文字符部分轉換爲全大寫或全小寫
String str="我愛java,LALALA"; String upper =str.toUpperCase(); System.out.println(upper);//我愛JAVA,LALALA String lower=str.toLowerCase(); System.out.println(lower);//我愛java,lalala
7、String trim()
-
去除字符串兩邊的空白字符
String str=" h e l l o "; System.out.println(str); // h e l l o String trim=str.trim(); System.out.println(trim);//hello System.out.println(str.trim());//hello
這兩個結果都是相同的,只是用法不一樣。
8、static String valueOf(XXX xxx)
-
字符串提供了一組靜態的重載的valueOf方法,作用
-
是將其他類型轉換爲字符串
int a=123; String s1=String.valueOf(a); System.out.println(s1);//123 double d=123.123; String s2=String.valueOf(d); System.out.println(s2);//123.123 String s3=a+""; System.out.println(s3);//123
補充StringBuffer的使用
String str="努力學習java";
StringBuilder b=new StringBuilder(str);
System.out.println(b);
增
/**
* 增
* append():將給定內容拼接到字符串末尾
*/
b.append(",爲了找個好工作!");
//獲取StringBuilder內部表示的字符串
str = b.toString();
System.out.println(str);
改
/**
* 改
* 怒力學習java,爲了找個好工作!
* 怒力學習java,就是爲了改變世界!
*/
b.replace(9,17,"爲了改變世界!");
System.out.println(b);
刪
/**
* 刪
*/
b.delete(0,9);
System.out.println(b);
插
/**
* 插:
*/
b.insert(0, "活着,就是");
System.out.println(b);
StringBuilder修改字符串性能
StringBuilder builder = new StringBuilder("a");
for(int i=0;i<100000000;i++){
builder.append("a");
}
System.out.println("執行完畢!");
這樣是在同一個變量改變,所以效率比較高,
StringBuufer是安全的,StringBuilder是不安全的。
---------------------------------------------------
String和正則表達式配合使用
關於正則表達式
大小寫不同,意思也就不同
\w [a-zA-Z0-9_] 單詞字符
\W 非單詞字符
\d [0-9] 任意一個數字
\D 非數字
\s 空白
\S 非空白
1、 String支持正則表達式的方法一:
- boolean matches(String regex)
- 使用給定的正則表達式驗證當前字符串是否符合格式
簡單判斷是否符合郵箱格式
//String email = "[email protected]";
String email="myweb/reg?username=xxx&password=xxx&....";
String regex="\\?";
/*
* \w+@[a-zA-Z0-9]+(\.[a-zA-Z]+)+;
* 使用字符串描述正則表達式
*/
//String regex="\\w+@[a-zA-Z0-9]+(\\.[a-zA-Z]+)";
boolean match=regex.equals(email);
if(match){
System.out.println("是郵箱");
}else {
System.out.println("不是郵箱");
}
2、 String 支持正則表達式方法二:
- String[] split(string regex)
- 將當前字符串按照滿足正則表達式的部分進行拆分,
- 將拆分後的部分以數組形式返回
拆分小例子
String line = "abc123bcd456efg789hji";
/*
* 按照數字部分拆分,得到所有的字母部分
*/
//String []arr1=line.split("[0-9]+");
/**
* 如果在拆分中出現了可連接的可拆分項 時,他們中間會拆分一個空字符串。
* 如果字符串開始就是拆分項時,前面也會拆分出 一個空字符串
* 注意:如果是字符串末尾連續匹配拆分項,那麼所有拆分出的空串全部忽略
*/
String []arr=line.split("[0-9]");
System.out.println(arr.length);
for(int i=0;i<arr.length;i++){
System.out.println(arr[i]);
}
String image ="123.png";
String []date=image.split("\\.");
image =date[1];
System.out.println(image);
3、 String 支持正則表達式三:
- String replaceALL(String regex ,String str)
- 將當前字符串中滿足正則表達式部分替換爲給定內容
替換小例子
String str1 = "abc123def456ghi789jkl";
/*
* 將數字部分替換爲"#NUMBER#"
*/
String str = str1.replaceAll("[0-9]+","#NUMBER#");
System.out.println(str);
4、和諧用語
當使用不文明語句,可以判斷是否符合條件,然後進行替換,
例子如下:
String regex = "(dsb|mdzz|cnm|wqnmlgb)";
String message = "wqnmlgb!cnm";
message = message.replaceAll(regex,"**");
System.out.println(message);