一、String
?? Java 中用 java.lang.String
類代表字符串
?? 底層用char[]
存儲字符數(shù)據。從 Java9 開始,底層使用 byte[]
存儲字符數(shù)據
public class TestDemo {
public static void main(String[] args) {
String bigBrother = "林哥"; // char[] value = {'林', '哥'};
}
}
?? 字符串的底層是
char[]
,但是 char 數(shù)組和字符串不能等價。char 數(shù)組是 char 數(shù)組,字符串是字符串。
?? C 語言中是可以把 char 數(shù)組和字符串等價的
?? 所有的 字符串字面量(如:"林哥"
)都是 String 類的實例
?? String 對象創(chuàng)建完畢后,String 對象的字符內容是不可以修改的
?? String 對象的引用變量的指向是可以修改的
public class TestDemo {
public static void main(String[] args) {
String s = "林哥";
s += "love";
s = "666";
test(s);
// s = 666
System.out.println("s = " + s);
}
private static void test(String str) {
// str 是局部變量, 生命周期只在 test 方法中
str += 123;
}
}
二、字符串常量池
?? 字符串常量池:String Constant Pool
?? 從 Java7 開始,字符串常量池是在堆空間(之前是在方法區(qū))
?? 當遇到字符串字面量的時候,會先在 SCP 中檢索
?? 看 SCP 中是否存在與字面量內容一樣的字符串對象 A ?
?? 如果有,返回字符串對象 A
?? 否則,創(chuàng)建一個新的字符串對象 B,并將其加入到 SCP 中,然后返回 B
public class TestDemo {
public static void main(String[] args) {
String s1 = "林哥";
String s2 = "林哥";
// true
System.out.println(s1 == s2);
}
}
三、字符串的初始化
public class TestDemo {
public static void main(String[] args) {
String s1 = "林哥";
String s2 = new String("林哥");
// 字符串對象 s3 的值和字符串對象 s1 的值是一樣的
// 底層指向的都是同一個 char 數(shù)組
String s3 = new String(s1);
String s4 = new String(s2);
char[] cs = {'林', '哥'};
String s5 = new String(cs);
String s6 = new String(s5);
}
}
String s1 = "林哥";
String s2 = new String("林哥");
?? 上面的兩行代碼中,字符串對象 s1 底層的 char 數(shù)組 value 和字符串對象 s2 底層的 char 數(shù)組是同一個
?? 如下圖所示:String 的構造方法會把傳入的字符串對象的 value 直接賦值給當前對象(當前創(chuàng)建的新字符串對象)的 value
可通過 debug 的方式驗證...
?? 上圖:字符串對象 s1 底層的 value 的 id 號是 541
?? 字符串對象 s2 底層的 value 的 id 號也是 541
—
?? 給 String 對象的構造方法傳入字符數(shù)組的時候,底層會拷貝一份該字符數(shù)組,然后才賦值給當前創(chuàng)建的 String 對象的 char 數(shù)組 value
四、String 類的 intern 方法
先看下面的代碼,思考打印結果:
public class TestDemo {
public static void main(String[] args) {
String s0 = "林哥";
String s1 = s0.intern();
// true
System.out.println(s1 == s0);
String s2 = new String(s0);
// false
System.out.println(s2 == s0);
String s3 = s2.intern();
System.out.println(s3 == s0); // true
System.out.println(s3 == s2); // false
}
}
?? 當字符串的
intern()
方法被調用的時候,如果字符串常量池中已經包含一個字符串對象的內容等于調用intern()
的字符串對象的內容,則返回字符串常量池中的字符串對象。否則,把調用intern()
的字符串對象添加到字符串常量池中,并返回該字符串對象(調用intern()
的字符串對象)
String s3 = s2.intern();
?? s2 調用了
intern()
方法,如果字符串常量池中存在與 s2 內容一樣的字符串對象 s 的話,返回字符串常量池中的 s 對象;否則,將 s2 添加到字符串常量池中,并返回 s2
只有遇到字符串字面量的時候,才會在字符串常量池中檢索
public class TestDemo {
public static void main(String[] args) {
int a = 1, b = 2, c = 3;
String s1 = String.format("%d_%d_%d", a, b, c);
String s2 = String.format("%d_%d_%d", a, b, c);
System.out.println(s1 == s2); // output: false
/*
只有【字符串字面量】才會在字符串常量池中找檢索
*/
}
}
public class TestDemo {
public static void main(String[] args) {
int a = 1, b = 2, c = 3;
String s1 = String.format("%d_%d_%d", a, b, c);
String s2 = String.format("%d_%d_%d", a, b, c);
System.out.println(s1 == s2); // output: false
/*
會把 s1 放入字符串常量池,并返回 s1 指向對象
s3 和 s1 指向的是同一個對象
*/
String s3 = s1.intern();
/*
會把被 s1 指向的字符串常量池中的字符串對象返回
s1 和 s4 指向的是同一個對象
*/
String s4 = s2.intern();
/*
返回字符串常量池中的字符串對象, 若 SCP 中沒有, 創(chuàng)建一個放入 SCP, 并返回
*/
String s5 = "1_2_3";
System.out.println(s1 == s3); // true
System.out.println(s1 == s4); // true
System.out.println(s1 == s5); // true
}
}
五、字符串常用方法
public class TestDemo {
public static void main(String[] args) {
// trim: 去除左右的空格
String s1 = " 111 2222 ".trim();
String s = "hAve A niCe Day";
// toUpperCase: 把小寫字母轉為大寫字母
String s2 = s.toUpperCase();
// toLowerCase: 把大寫字母轉換為小寫字母
String s3 = s.toLowerCase();
// contains: 是否包含某個子字符串片段
boolean contains = "Have a nice Day".contains("nice");
// startsWith: 是否以某個子字符串片段開頭
boolean startsWith = "Love is love.".startsWith("love");
// endsWith: 是否以某個子字符串片段結尾
boolean endsWith = "Love is love".endsWith("love");
// 將字符串分隔為字符串數(shù)組
String[] split = "Today_we_have_a_new_student".split("_");
// output: [Today, we, have, a, new, student]
System.out.println(Arrays.toString(split));
}
}
字符串的截取:
public class TestDemo {
public static void main(String[] args) {
String nice = "goodMorning";
// 從下標 4 位置開始截取, 截取到最后
String s1 = nice.substring(4);
// output: s1 = Morning
System.out.println("s1 = " + s1);
String s = "believe";
// 從下標 2 位置開始截取, 截取到下標為 5 的位置(不包括下標5位置的字符)
// 左閉右開
String s2 = s.substring(2, 5);
// s2 = lie
System.out.println("s2 = " + s2);
}
}
indexOf: 定位字符串所在索引
public class TestDemo {
public static void main(String[] args) {
int result1 = "hello".indexOf("e");
int result2 = "hello".indexOf("a");
System.out.println(result1); // 1
System.out.println(result2); // -1
}
}
?? 如果字符串中不包含該子字符串,返回 -1
lastIndexOf: 定位字符串所在索引
public class TestDemo {
public static void main(String[] args) {
// 從左往右開始定位字符串索引
int result1 = "hello log".indexOf("lo");
// 從右往左開始定位字符串索引(但數(shù)的時候還是從左往右數(shù))
int result2 = "hello log".lastIndexOf("lo");
System.out.println(result1); // 3
System.out.println(result2); // 6
}
}
字符串替換:
public class TestDemo {
public static void main(String[] args) {
String s1 = "I live you";
String s2 = s1.replace("live", "like");
// s1 = I live you
System.out.println("s1 = " + s1);
// s2 = I like you
System.out.println("s2 = " + s2);
}
}
六、StringBuilder 和 StringBuffer
?? 需要進行大量的字符串改動操作(如拼接、替換)的時候,使用 String 會非常消耗內存、會降低程序性能
??StringBuilder 或 StringBuffer 進行大量字符串拼接或替換的時候,程序性能和內存的消耗特別小
public class TestDemo {
public static void main(String[] args) {
String s = "1";
s += "2";
s += "3";
s += "4";
// s = 1234
System.out.println("s = " + s);
}
}
?? 上面代碼,每一次的拼接操作都會產生一個新的字符串對象
?? 由于字符串內容的不可變性,每次的拼接操作必定都會產生一個新的字符串對象(如上圖),會存在大量的字符串對象的創(chuàng)建和銷毀操作
public class TestDemo {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder("1");
sb.append("2");
sb.append("3");
sb.append("4");
// 1234
System.out.println(sb.toString());
// 鏈式調用
StringBuffer sBuffer = new StringBuffer("1")
.append("2")
.append("3")
.append("4");
// 1234
System.out.println(sBuffer);
}
}
?? 使用 StringBuilder 和 StringBuffer 則會非常高效
?? StringBuilder 和 StringBuffer 的使用方式(API)都一樣
?? 區(qū)別:StringBuilder 線程不安全;StringBuffer 線程安全
?? 常用方法:append、insert、delete、replace、reverse
?? StringBuider 或 StringBuffer 與 String 并不存在繼承關系
?? StringBuilder、StringBuffer、String 都實現(xiàn)了 CharSequence 接口
?? StringBuilder 的 append 原理:動態(tài)數(shù)組
動態(tài)數(shù)組的實現(xiàn)博主后期在學習,后期再寫文章
文章來源:http://www.zghlxwxcb.cn/news/detail-405351.html
結束,如有錯誤請不吝賜教
文章來源地址http://www.zghlxwxcb.cn/news/detail-405351.html
到了這里,關于36、Java 中的 String、StringBuilder、StringBuffer、字符串常量池和 intern 方法的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!