字符串操作是計算機程序設計中最常見的行爲,所以掌握好String類的使用很重要。
String是一個final修飾的類,所以它是不可以被繼承的,String對象是不可以變的,也就是說創建了一個對象以後,那麼這個對象的長度是不可以修改的,而我們平時進行的字符串拼接、修改等操作都只是拷貝了它的引用,並不會改變原字符串的大小。
下面通過一段代碼來了解一個String的創建對象;
//創建String對象
String str="yxc";
String str2="yxc";
String str1=new String("yxc");
String str3=new String("yxc");
System.out.println(str1==str3);
System.out.println(str==str2);
System.out.println(str==str1);
返回結果:
false
true
false
可能初學者有點困惑,那麼下面通過圖解來分析(還在尋找合適的畫圖軟件,暫時手動畫:)
首先對於str和str2來說,在常量池創建一個“yxc”常量,然後將它的地址給str,str2.
而str1和str3來說,首先使用new關鍵字在堆內存在創建一個對象,然後把堆內存的引用傳給str1和str3 而後面傳進來的參數是常量池中的引用。
再看下面的一段代碼:
String str1="hello world";
String str2=str1.substring(2);
System.out.println(str2);
System.out.println(str1);
運行結果:
llo world
hello world
對於substring函數是截取字符串,後面的參數表示索引,從哪開始截取,這個我們後續再說,這裏想要說的是,我們修改了通過str.substring(),但是原來的字符串str1其實根本沒有改變,這就是字符串的不可變成,其實這種設計正是我們需要的,很多時候我們不希望修改原來的值。對於字符串中的函數通常都是如果操作成功返回一個新的對象,如果沒有就返回原來的對象,這樣節約了很多空間,怎麼說的,看下面代碼:
tring str1="hello world";
String str2=str1.substring(0);
String str3=str1.substring(1);
System.out.println(str1==str3);
System.out.println(str1==str2);
結果返回:
false
true
對吧,這就說明了返回原對象和返回一個新的對象。字符竄中很多方法都是這樣設計的,下面我們學習一下String中常用的方法。通過一段代碼加上詳細的註釋直接搞定:
package com.yxc.string;
//測試String中常見的方法
public class StringProject {
public static void main(String[] args) {
System.out.println("其它數據類型轉爲String類型測試");
//將其它數據類型轉爲字符串
double d=123456.7;
String str1 = String.valueOf(d);
System.out.println(str1); //123456.7
//其它的數據類型都是一樣的,只是換一下數據類型就可以
//這裏還有一種稍微特殊一點的
char[] c=new char[]{'a','y','z','w'};
//從下標爲1開始截取,截取兩個,然後將這兩個轉換爲字符串
String str2 = String.valueOf(c, 1, 2);
System.out.println(str2); //yz
System.out.println("字符串轉爲其它數據類型");
String str3="3121";
int j = Integer.parseInt(str3);
System.out.println(j); //3121
//其它的數據類型類似
System.out.println("計算字符串長度");
System.out.println(str3.length());//注意length是方法,不是數據中的屬性
System.out.println("字符串開頭和結尾 返回boolean類型");
String str4="jamesy";
System.out.println(str4.startsWith("j"));//true
System.out.println(str4.endsWith("k")); //false
System.out.println("索引");
/**
* 索引元素,如果存在返回字符串所在的下標,下標從零開始 如果不存在返回-1
* 如果是從後面索引,如果找到也是返回下標嗎,而是是從前往後的下標(注意)
* 如果有相同的就返回第一個查找的的
*/
String str5="I will give you some color to see see";
System.out.println(str5.indexOf("give"));
System.out.println(str5.lastIndexOf("give")); //返回結果也是7
System.out.println(str5.indexOf("see")); //30
System.out.println(str5.lastIndexOf("see")); //34
//所以索引see的時候肯定是不一樣的,從前往後索引和從後索引第一個出現的see的位置不一樣
System.out.println("忽略大小寫比較");
System.out.println("hello".equalsIgnoreCase("HeLLo"));//true
System.out.println("根據位置索引值");
System.out.println("asdfg".charAt(3)); //f
System.out.println("將字符串轉爲字符數組");
String str6="just do it";
char[] chars = str6.toCharArray();
for(int i=0;i<chars.length;i++){
System.out.print(chars[i]);
}
System.out.println("截取字符串");
String str7="justsoso";
String substring = str7.substring(2, 5); //sts 從2截取到5
System.out.println(substring);
System.out.println("連接字符串");
System.out.println("yxc".concat("xin"));
System.out.println("將字符串轉爲字節數組");
String str8="yuio";
byte[] bytes = str8.getBytes();
for(int i=0;i<bytes.length;i++){
System.out.print(bytes[i]+" "); //121 117 105 111
}
System.out.println("是否包含某一個對象");
String str9="yangxinchun";
String str10="xin";
System.out.println(str9.contains(str10)); //true
}
}
String類確實經常使用,但是有些情況使用它的效率會很低,看下面一段代碼:
long startTime = System.currentTimeMillis();
String str="yxc";
for(int i=1;i<100000;i++){
str=str+i;
}
long endTime=System.currentTimeMillis();
System.out.println(endTime-startTime);
在我機器上硬是跑了40977ms,(我測試了下10000000,幾分鐘沒跑出來我就關閉了)這才十萬級別,而且更可怕的是上面的操作會產生十萬多個對象。這樣的效率太低而且消耗資源,因爲對象的創建是很耗資源的,只是爲了拼接一個字符上去就要產生一個新的對象,這樣的設計顯然不和實際,所以java中有加強String類中字符串拼接的類,StringBuffer和StringBuilder,同樣我們測試一下時間:
long startTime = System.currentTimeMillis();
String str="yxc";
StringBuilder str1=new StringBuilder(str);
for(int i=1;i<100000;i++){
str1.append(i);
}
long endTime=System.currentTimeMillis();
System.out.println(endTime-startTime);
耗時27ms
long startTime = System.currentTimeMillis();
String str="yxc";
StringBuffer str1=new StringBuffer(str);
for(int i=1;i<100000;i++){
str1.append(i);
}
long endTime=System.currentTimeMillis();
System.out.println(endTime-startTime);
耗時33ms,所以可以看出來,在字符串拼接上面,後兩者的效率提高的不只是幾個檔次了,而對於後面兩者StringBuilder的效率還會高一點,但是它是線程不安全的,而Stringbuffer是線程安全的。
StringBuffer str=new StringBuffer("abcdefg");
//stringbuffer中常見的方法
System.out.println("插入一個元素在字符串中");
StringBuffer str1 = str.insert(2, "poi");
System.out.println(str1); //abpoicdefg
//和String不一樣,str的值發生了改變
System.out.println(str); //abpoicdefg
//也就是說兩者的對象時一樣的
System.out.println(str==str1); //true
System.out.println("字符串的反轉");
System.out.println(str.reverse()); //gfedciopba
System.out.println("字符串的刪除");
StringBuffer str3 = str.delete(3, 6);
System.out.println(str3); //gfeopba
StringBuilder和StringBuffer是一樣的,而且String有的方法這兩個類基本也有,可以看成是對於String的擴展類,但是不是繼承,因爲String是final修飾的類,不能被繼承。注意上面的代碼操作的都是一個對象,修改以後,StringBuffer的對象一直在改變。