String
String類頭
public final class String extends Object implements Serializable, Comparable<String>,
CharSequence
子串
public String substring(int beginIndex, int endIndex)
String greeting = "Hello";
//修改字符串變量
greeting = greeting.substring(0,3);
substring第二個參數(shù)為不想賦值的第一個位置四瘫。此函數(shù)賦值0飒焦、1、2躺翻。
拼接
“+”可以實現(xiàn)String的拼接。當(dāng)一個字符串與一個非字符串進(jìn)行拼接時卫玖,后者被轉(zhuǎn)換為字符串公你。
//拼接字符串
int age = 13;
String rating = "PG" + age;
System.out.println(rating);
關(guān)于 equal 和 ==
== 用于比較兩個對象的時候,是來check 是否兩個引用指向了同一塊內(nèi)存假瞬。equals() 是object的方法陕靠,默認(rèn)情況下,它與== 一樣脱茉,比較的地址剪芥。但是當(dāng)equal被重載之后,根據(jù)設(shè)計琴许,equal 會比較對象的value税肪。而這個是java希望有的功能。
//測試equals和==
//以字面常量測試
String obj1 = "Hello";
String obj2 = "Hello";
if(obj1 == obj2){
System.out.println("obj1 == obj2: "+"true");
}
else {
System.out.println("obj1 == obj2: "+"false");
}
if(obj1.equals(obj2)){
System.out.println("obj1.equals(obj2): "+"true");
}
else {
System.out.println("obj1.equals(obj2): "+"false");
}
//以new創(chuàng)建對象測試
String obj3 = new String("Hello");
String obj4 = new String("Hello");
if(obj3 == obj4){
System.out.println("obj3 == obj4: "+"true");
}
else {
System.out.println("obj3 == obj4: "+"false");
}
if(obj3.equals(obj4)){
System.out.println("obj3.equals(obj2): "+"true");
}
else {
System.out.println("obj4.equals(obj2): "+"false");
}
運行結(jié)果:
obj1 == obj2: true
obj1.equals(obj2): true
obj3 == obj4: false
obj3.equals(obj2): true
常量池
如果使用字面量創(chuàng)建一個String對象時,它將返回一個位于字符串常量池中的引用益兄,如果該字面量已經(jīng)存在于常量池(String Pool)中锻梳,則無需重新新建,只需要已有的字面量净捅,否則將新建一個字面量疑枯。
jdk1.7之前,String Pool位于堆中的永久去內(nèi)灸叼,從jdk1.7開始神汹,String Pool遷移到主堆中。
//測試String Pool
String s1 = new String("java");
String s2 = new String("java");
String s3 = "java";
String s4 = "java";
s1 == s2: false
s1.equals(s2): true
s3 == s4: true
String & StringBuffer & StringBuilder
- String:是不可改變的量古今,也就是創(chuàng)建后就不能在修改了屁魏。
- StringBuffer:是一個可變字符串序列,它與 String 一樣捉腥,在內(nèi)存中保存的都是一個有序的字符串序列(char 類型的數(shù)組)氓拼,不同點是 StringBuffer 對象的值都是可變的。
- StringBuilder:與 StringBuffer 類基本相同抵碟,都是可變字符換字符串序列桃漾,不同點是 StringBuffer 是線程安全的,StringBuilder 是線程不安全的拟逮。
使用場景
- String:在字符串不經(jīng)常變化的場景中可以使用 String 類撬统,例如常量的聲明、少量的變量運算敦迄。
- StringBuffer:在頻繁進(jìn)行字符串運算(如拼接恋追、替換、刪除等)罚屋,并且運行在多線程環(huán)境中苦囱,則可以考慮使用 StringBuffer,例如 XML 解析脾猛、HTTP 參數(shù)解析和封裝撕彤。
- StringBuilder:在頻繁進(jìn)行字符串運算(如拼接、替換猛拴、和刪除等)羹铅,并且運行在單線程的環(huán)境中,則可以考慮使用 StringBuilder愉昆,如 SQL 語句的拼裝职员、JSON 封裝等。
運行速度
StringBuilder > StringBuffer>String
在正常情況下撼唾,每次對 String 類型進(jìn)行改變的時候其實都等同于生成了一個新的 String 對象廉邑,然后將指針指向新的 String 對象,所以經(jīng)常改變內(nèi)容的字符串最好不要用 String 倒谷,因為每次生成對象都會對系統(tǒng)性能產(chǎn)生影響蛛蒙,特別當(dāng)內(nèi)存中無引用對象多了以后, JVM 的 GC 就會開始工作渤愁,那速度是一定會相當(dāng)慢的牵祟。
而如果是使用 StringBuffer 類則結(jié)果就不一樣了,每次結(jié)果都會對 StringBuffer 對象本身進(jìn)行操作抖格,而不是生成新的對象诺苹,再改變對象引用。所以在一般情況下我們推薦使用 StringBuffer 雹拄,特別是字符串對象經(jīng)常改變的情況下收奔。而在某些特別情況下, String 對象的字符串拼接其實是被 JVM 解釋成了 StringBuffer 對象的拼接滓玖,所以這些時候 String 對象的速度并不會比 StringBuffer 對象慢坪哄。
final static int ttimes = 3000;// 設(shè)置循環(huán)次數(shù)
// String測試,對String使用‘+’添加字面常量
public void test(String s) {
long begin = System.currentTimeMillis();
for (int i = 0; i < ttimes; i++) {
s += "add";
}
long over = System.currentTimeMillis();
System.out.println(" 操作 " + s.getClass().getName() + " 類型使用的時間為: "
+ (over - begin) + " 毫秒 ");
}
// String測試,對String直接進(jìn)行字符串拼接
public void test2() {
String s2 = "abcdefg";
long begin = System.currentTimeMillis();
for (int i = 0; i < ttimes; i++) {
String s = s2 + s2 +s2;
}
long over = System.currentTimeMillis();
System.out.println(" 操作字符串對象引用相加類型使用的時間為: " + " 類型使用的時間為: "
+ (over - begin) + " 毫秒 ");
}
// String測試,對String直接進(jìn)行字符串拼接
public void test3() {
long begin = System.currentTimeMillis();
for (int i = 0; i < ttimes; i++) {
String s = "abcdefg" + "abcdefg" +"abcdefg";
}
long over = System.currentTimeMillis();
System.out.println("操作字符串對象引用相加類型使用的時間為: " + " 類型使用的時間為: "
+ (over - begin) + " 毫秒 ");
}
// StringBuffer測試
public void test(StringBuffer s) {
long begin = System.currentTimeMillis();
for (int i = 0; i < ttimes; i++) {
s.append("add");
}
long over = System.currentTimeMillis();
System.out.println(" 操作 " + s.getClass().getName() + " 類型使用的時間為: "
+ (over - begin) + " 毫秒 ");
}
// StringBuilder測試
public void test(StringBuilder s) {
long begin = System.currentTimeMillis();
for (int i = 0; i < ttimes; i++) {
s.append("add");
}
long over = System.currentTimeMillis();
System.out.println(" 操作 " + s.getClass().getName() + " 類型使用的時間為: "
+ (over - begin) + " 毫秒 ");
}
String s1 ="abc";
StringBuffer sb1 = new StringBuffer("abc");
StringBuilder sb2 = new StringBuilder("abc");
Main t = new Main();
t.test(s1);
t.test(sb1);
t.test(sb2);
t.test2();
t.test3();
操作 java.lang.String 類型使用的時間為: 47 毫秒
操作 java.lang.StringBuffer 類型使用的時間為: 2 毫秒
操作 java.lang.StringBuilder 類型使用的時間為: 1 毫秒
操作字符串對象引用相加類型使用的時間為: 類型使用的時間為: 6 毫秒
操作字符串相加類型使用的時間為: 類型使用的時間為: 0 毫秒
實驗證明:
StringBuffer與StringBuilder速度相差不大,兩者速度明顯高于String势篡;
String直接使用字符串相加時翩肌,JVM會默認(rèn)為把幾個字符串加在一起,運行速度較快禁悠,但是使用引用相加時需要創(chuàng)建新的對象念祭,比較耗時。