目錄
Java的字符串的基礎(chǔ)知識(必看)
String
API的使用
String概述
創(chuàng)建String對象的兩種方式
==號比的是什么?
難點
經(jīng)典String案例
易錯點
StringBuilder
疑難點:
StringJoiner
字符串相關(guān)類的底層原理
中文的存儲原理
String的常見的構(gòu)造方法
Java的字符串的基礎(chǔ)知識(必看)
String
API的使用
JavaAPI(Java Application Programming Interface)是Java編程語言提供的一組類庫和接口,用于開發(fā)Java應(yīng)用程序。它為開發(fā)人員提供了訪問Java平臺功能的標(biāo)準(zhǔn)方式。JavaAPI包含了大量的類和接口,用于處理各種任務(wù),包括文件操作、網(wǎng)絡(luò)通信、圖形用戶界面(GUI)開發(fā)、數(shù)據(jù)庫訪問、多線程編程等。
JavaAPI是Java語言的核心部分,它定義了Java平臺的基本構(gòu)建塊,使開發(fā)人員能夠利用Java的強大功能。JavaAPI以包(package)的形式組織,每個包包含一組相關(guān)的類和接口。開發(fā)人員可以通過導(dǎo)入所需的包來使用JavaAPI中的類和接口。
JavaAPI的設(shè)計目標(biāo)是提供簡單、一致和易于使用的編程接口,以加快開發(fā)速度并降低開發(fā)難度。它提供了豐富的功能,使開發(fā)人員能夠快速構(gòu)建各種類型的應(yīng)用程序,從簡單的命令行工具到復(fù)雜的企業(yè)級應(yīng)用程序。
JavaAPI還具有良好的跨平臺性,因為Java程序可以在不同的操作系統(tǒng)上運行,只要目標(biāo)系統(tǒng)上有Java運行時環(huán)境(Java Runtime Environment,JRE)即可。這使得JavaAPI成為廣泛應(yīng)用于各種領(lǐng)域的編程工具,包括桌面應(yīng)用程序、移動應(yīng)用程序、Web應(yīng)用程序、嵌入式系統(tǒng)等。
總之,JavaAPI是Java編程語言提供的一組類庫和接口,用于開發(fā)Java應(yīng)用程序。它提供了豐富的功能和簡單易用的編程接口,使開發(fā)人員能夠快速構(gòu)建各種類型的應(yīng)用程序,并具有良好的跨平臺性。
JRE(Java Runtime Environment)是Java運行時環(huán)境的縮寫,它是Java應(yīng)用程序的運行環(huán)境。JRE包含了Java虛擬機(Java Virtual Machine,JVM)以及Java類庫和其他支持文件,用于執(zhí)行Java程序。
當(dāng)你編寫一個Java程序并打算運行它時,你需要先安裝JRE。JRE提供了Java程序所需的運行時環(huán)境,包括Java虛擬機,它是執(zhí)行Java字節(jié)碼的虛擬計算機。Java虛擬機負責(zé)解釋和執(zhí)行Java程序的字節(jié)碼,并提供了內(nèi)存管理、安全性、線程管理等功能。
除了Java虛擬機,JRE還包含了一系列的Java類庫,這些類庫提供了豐富的功能和工具,用于開發(fā)和執(zhí)行Java程序。這些類庫涵蓋了各種領(lǐng)域,包括文件操作、網(wǎng)絡(luò)通信、圖形用戶界面(GUI)開發(fā)、數(shù)據(jù)庫訪問、多線程編程等。
JRE的安裝通常是隨同Java開發(fā)工具包(Java Development Kit,JDK)一起提供的。JDK是用于開發(fā)Java應(yīng)用程序的工具包,它包含了JRE以及其他開發(fā)工具,如編譯器(javac)、調(diào)試器(jdb)等。在開發(fā)階段,開發(fā)人員通常需要安裝JDK來編譯、調(diào)試和運行Java程序。而在部署階段,只需要安裝JRE來執(zhí)行已經(jīng)編譯好的Java程序。
總之,JRE是Java運行時環(huán)境,它包含了Java虛擬機和Java類庫,用于執(zhí)行Java程序。安裝JRE可以提供Java程序所需的運行時環(huán)境,使得Java程序能夠在計算機上正確運行。
String概述
String name = "123";
name = "456";
System.out.println(name);
運行結(jié)果:
這幾行代碼展示了Java中對字符串(String)對象的操作。
首先,代碼創(chuàng)建了一個名為name
的字符串變量,并將其初始化為"123",即String name = "123";
。
接下來,代碼將字符串變量name
的值修改為"456",即name = "456";
。在Java中,字符串是不可變的(immutable),這意味著一旦創(chuàng)建了一個字符串對象,就無法修改它的值。但是,當(dāng)我們修改字符串變量時,實際上是創(chuàng)建了一個新的字符串對象,并將變量指向新的對象。
最后,代碼使用System.out.println()
方法將字符串變量name
的值打印到控制臺。由于name
的值已經(jīng)被修改為"456",所以打印的結(jié)果是"456"。
因此,這幾行代碼的執(zhí)行結(jié)果是在控制臺輸出"456"。
在Java中,字符串常量(如"456")在編譯時會被放入字符串常量池(String Pool)中,而不是在堆(Heap)中分配空間。字符串常量池是一塊特殊的內(nèi)存區(qū)域,用于存儲字符串常量的引用。
當(dāng)執(zhí)行name = "456";
時,Java會檢查字符串常量池中是否已經(jīng)存在值為"456"的字符串對象。如果存在,那么變量name
會指向字符串常量池中的對象;如果不存在,Java會在字符串常量池中創(chuàng)建一個新的字符串對象,并讓變量name
指向它。
因此,在這段代碼中,變量name
實際上指向了字符串常量池中的對象,而不是在堆中分配新的空間。這是因為字符串常量是不可變的,可以被共享和重復(fù)使用。這種設(shè)計有助于提高性能和節(jié)省內(nèi)存。
需要注意的是,如果使用new
關(guān)鍵字創(chuàng)建字符串對象,例如String name = new String("456");
,那么會在堆中分配新的空間來存儲字符串對象。這種情況下,字符串常量池中不會有對應(yīng)的對象,而是在堆中創(chuàng)建一個新的對象。但是,在一般情況下,推薦使用字符串常量來初始化字符串變量,以便利用字符串常量池的優(yōu)勢。
字符串常量池(String Pool)是Java中的一塊特殊內(nèi)存區(qū)域,用于存儲字符串常量。它是在運行時存儲字符串對象的一個緩存區(qū)域。
在Java中,當(dāng)我們使用字符串字面量(如"hello")創(chuàng)建字符串對象時,Java會首先檢查字符串常量池中是否已經(jīng)存在相同內(nèi)容的字符串對象。如果存在,那么新的字符串對象將直接引用已存在的對象,而不會創(chuàng)建新的對象;如果不存在,Java會在字符串常量池中創(chuàng)建一個新的字符串對象,并將其放入常量池中。
通過使用字符串常量池,Java實現(xiàn)了字符串的共享和重用。這樣做有助于提高性能和節(jié)省內(nèi)存,因為多個字符串變量可以共享同一個字符串常量,而不需要每次都創(chuàng)建新的對象。
需要注意的是,字符串常量池是存儲在堆中的一部分,而不是存儲在棧中。這意味著字符串常量池中的字符串對象在垃圾回收時不會被回收,除非整個字符串常量池被清空。
總之,字符串常量池是Java中用于存儲字符串常量的緩存區(qū)域,它提供了字符串對象的共享和重用機制,以提高性能和節(jié)省內(nèi)存。
在Java中,變量存儲的是對象的引用,而不是對象本身。當(dāng)我們聲明一個變量并將其賦值為一個字符串對象時,變量實際上保存的是字符串對象在內(nèi)存中的引用地址。
在字符串常量池中,每個字符串常量都有一個唯一的引用地址。當(dāng)我們將一個字符串常量賦值給一個變量時,變量會保存該字符串常量的引用地址。這樣做的好處是,可以通過變量來訪問和操作字符串對象,而不需要直接操作引用地址。
例如,當(dāng)我們執(zhí)行以下代碼:
String name = "456";
變量name
會保存字符串常量"456"在字符串常量池中的引用地址。
通過使用引用地址,Java可以實現(xiàn)字符串的共享和重用。如果多個變量都指向同一個字符串常量,它們實際上指向的是相同的對象,而不是每個變量都擁有一個獨立的對象。這樣可以節(jié)省內(nèi)存空間,并提高性能。
總結(jié)起來,變量保存的是對象的引用地址,而不是直接保存對象本身或字符串常量的地址。這樣可以通過變量來訪問和操作對象,同時實現(xiàn)對象的共享和重用。
在Java中,對象的引用地址和字符串常量的地址實際上是同一個概念,都表示對象在內(nèi)存中的位置。引用地址是一個唯一標(biāo)識對象的值,可以用來定位和訪問對象。
區(qū)別在于對象的引用地址和字符串常量的地址所指向的內(nèi)容不同。
-
對象的引用地址指向堆內(nèi)存中的對象實例。當(dāng)我們使用
new
關(guān)鍵字創(chuàng)建一個對象時,Java會在堆中為該對象分配內(nèi)存空間,并返回該對象在堆中的引用地址。我們可以通過該引用地址來訪問和操作對象的屬性和方法。 -
字符串常量的地址指向字符串常量池中的字符串對象。字符串常量池是一個存儲字符串常量的緩存區(qū)域,用于存儲在代碼中直接使用的字符串字面量。當(dāng)我們使用字符串字面量創(chuàng)建字符串對象時,Java會首先檢查字符串常量池中是否已經(jīng)存在相同內(nèi)容的字符串對象。如果存在,新的字符串對象將直接引用已存在的對象;如果不存在,Java會在字符串常量池中創(chuàng)建一個新的字符串對象,并將其放入常量池中。因此,字符串常量的地址指向的是字符串常量池中的對象。
需要注意的是,字符串常量池是存儲在堆中的一部分,而不是存儲在棧中。因此,字符串常量的地址和對象的引用地址都指向堆內(nèi)存中的對象實例,只是它們指向的具體位置不同。
總結(jié)起來,對象的引用地址和字符串常量的地址都表示對象在內(nèi)存中的位置,但對象的引用地址指向堆內(nèi)存中的對象實例,而字符串常量的地址指向字符串常量池中的對象。
因此,System.out.println(name);
語句輸出的是name
變量當(dāng)前所引用的字符串常量的內(nèi)容,即"456",而不是name
變量所指向的地址.
在Java中,System.out.println()
方法會根據(jù)參數(shù)的類型進行適當(dāng)?shù)霓D(zhuǎn)換和輸出。對于字符串類型的參數(shù),它會輸出字符串的內(nèi)容而不是引用地址。
創(chuàng)建String對象的兩種方式
是的,String
是Java中的引用數(shù)據(jù)類型。在Java中,基本數(shù)據(jù)類型(如整數(shù)、浮點數(shù)等)是直接存儲值的,而引用數(shù)據(jù)類型(如 String
、數(shù)組、對象等)存儲的是對象的引用或地址。
當(dāng)我們聲明一個 String
類型的變量時,實際上是在棧內(nèi)存中創(chuàng)建了一個變量,該變量存儲了字符串對象的引用。這個引用指向存儲在堆內(nèi)存中的實際字符串對象。
例如,以下代碼中的 str
是一個 String
類型的引用變量:
String str = "Hello";
這里,str
存儲了字符串 "Hello"
對象的引用。實際的字符串對象被存儲在字符串常量池或堆內(nèi)存中,而 str
只是指向該對象的引用。
因為 String
是引用數(shù)據(jù)類型,所以可以對字符串對象進行各種操作,例如拼接、截取、比較等。同時,由于字符串的不可變性,每次對字符串進行修改操作時,實際上是創(chuàng)建了一個新的字符串對象,而原始的字符串對象保持不變。
總結(jié)起來,String
是Java中的引用數(shù)據(jù)類型,用于表示字符串對象,并提供了豐富的字符串操作方法。
==號比的是什么?
在Java中,==
運算符用于比較兩個對象的引用是否相等,而不是比較對象的內(nèi)容。具體來說,==
比較的是兩個對象的內(nèi)存地址是否相同。
當(dāng)使用 ==
比較兩個引用類型的變量時,會進行如下判斷:
- 如果兩個引用變量指向同一個對象(即它們的內(nèi)存地址相同),則
==
返回true
。 - 如果兩個引用變量指向不同的對象(即它們的內(nèi)存地址不同),則
==
返回false
。
這里需要注意的是,對于基本數(shù)據(jù)類型(如 int
、double
等),==
比較的是它們的值是否相等,而不是比較內(nèi)存地址。
如果我們想要比較兩個字符串對象的內(nèi)容是否相等,應(yīng)該使用 equals()
方法,而不是 ==
運算符。equals()
方法是在 Object
類中定義的,子類可以覆蓋它以提供自定義的相等判斷邏輯。在 String
類中,equals()
方法已經(jīng)被重寫,用于比較字符串對象的內(nèi)容是否相等。
例如,以下示例演示了 ==
運算符和 equals()
方法的使用:
String str1 = "Hello";
String str2 = "Hello";
String str3 = new String("Hello");
System.out.println(str1 == str2); // 輸出 true,因為兩個引用變量指向同一個字符串常量池中的對象
System.out.println(str1 == str3); // 輸出 false,因為兩個引用變量指向不同的對象
System.out.println(str1.equals(str2)); // 輸出 true,因為兩個字符串對象的內(nèi)容相等
System.out.println(str1.equals(str3)); // 輸出 true,因為兩個字符串對象的內(nèi)容相等
總之,==
運算符比較的是對象的引用是否相等,而 equals()
方法比較的是對象的內(nèi)容是否相等。
難點
在Java中,當(dāng)一個字符串與其他類型的數(shù)據(jù)進行連接操作時,Java會自動將其他類型的數(shù)據(jù)轉(zhuǎn)換為字符串。這個過程稱為字符串的拼接或字符串的連接。
在代碼中,表達式s = s + 12;中,整數(shù)12會自動轉(zhuǎn)換為字符串"12",然后與字符串s連接在一起,形成新的字符串"[12"。
經(jīng)典String案例
package com.xiaonan.exercise06;
import java.util.Scanner;
public class Demo07 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("請輸入您的身份證號");
//在while外定義 身份證號
String idCard;
while(true){
idCard = sc.next();
if(idCard.length()!=18){
System.out.println("您輸入的身份證號碼有誤,請重新輸入");
}else {
System.out.println("輸入成功");
break;
}
}
//1. 獲取出生年月日
String year = idCard.substring(6,10);
String month = idCard.substring(10,12);
String day = idCard.substring(12,14);
//2. 獲取性別
String gender = idCard.substring(16,17);
char c = gender.charAt(0);
//這里的test的值為 ASCII碼值 不是真正的"數(shù)字"
//我要拿的是里面的之前存儲的數(shù)字1,2 來計算 而不是拿數(shù)字對應(yīng)的碼值來計
int test = (int)c; //所以這是錯的
System.out.println("--------"+test);
//**注意點1, 這里要轉(zhuǎn)化**
if((c-'0')%2==0){
gender = "女";
}else{
gender = "男";
}
//3. 輸出
System.out.println("人物信息為");
System.out.println(year+"年"+month+"月"+day+"日");
System.out.println("性別為: "+gender);
}
}
易錯點
//2. 獲取性別 String gender = idCard.substring(16,17); char c = gender.charAt(0); //這里的test的值為 ASCII碼值 不是真正的"數(shù)字" //我要拿的是里面的之前存儲的數(shù)字1,2 來計算 而不是拿數(shù)字對應(yīng)的碼值來計 int test = (int)c; //所以這是錯的 System.out.println("--------"+test); //注意點1, 這里要轉(zhuǎn)化 if((c-'0')%2==0){ gender = "女"; }else{ gender = "男"; }
StringBuilder
在Java中,你可以使用 StringBuilder
類來構(gòu)建可變的字符串。StringBuilder
允許你進行字符串的修改和拼接,而不需要創(chuàng)建新的字符串對象。
下面是使用 StringBuilder
進行字符串替換的示例:
String talk = "Hello, world!";
String[] arr = {"Hello", "world"};
StringBuilder sb = new StringBuilder(talk);
for (String word : arr) {
int index = sb.indexOf(word);
while (index != -1) {
sb.replace(index, index + word.length(), "***");
index = sb.indexOf(word, index + 1);
}
}
String result = sb.toString();
System.out.println(result);
在上面的示例中,我們首先創(chuàng)建了一個 StringBuilder
對象 sb
,并將初始字符串 talk
傳遞給它的構(gòu)造函數(shù)。然后,我們使用 indexOf
方法找到要替換的字符串的位置,并使用 replace
方法將其替換為 "***"
。我們使用 indexOf
方法的第二個參數(shù)來查找下一個出現(xiàn)的位置,并在循環(huán)中重復(fù)這個過程,直到找不到更多的匹配。
最后,我們使用 toString
方法將 StringBuilder
對象轉(zhuǎn)換回普通的字符串,并將結(jié)果打印出來。
使用 StringBuilder
可以避免每次替換都創(chuàng)建新的字符串對象,從而提高性能和效率。
-
打印對象不是地址值,而是屬性值
-
StringBuilder容器里的值是可以改的,而String是不可以改的,String需要創(chuàng)建新的字符串(重復(fù)就不用創(chuàng)建,兩個對象都會指向這個字符串)
在Java中,
String
和StringBuilder
都提供了一些常用的方法來操作字符串。下面是它們的一些常用方法:String常用方法:
-
length()
:返回字符串的長度。 -
charAt(int index)
:返回指定索引位置的字符。 -
substring(int beginIndex)
:返回從指定索引開始到字符串末尾的子字符串。 -
substring(int beginIndex, int endIndex)
:返回從指定索引開始到指定索引結(jié)束的子字符串。 -
indexOf(String str)
:返回指定字符串在當(dāng)前字符串中第一次出現(xiàn)的索引位置。 -
lastIndexOf(String str)
:返回指定字符串在當(dāng)前字符串中最后一次出現(xiàn)的索引位置。 -
startsWith(String prefix)
:檢查當(dāng)前字符串是否以指定的前綴開始。 -
endsWith(String suffix)
:檢查當(dāng)前字符串是否以指定的后綴結(jié)束。 -
toUpperCase()
:將字符串轉(zhuǎn)換為大寫。 -
toLowerCase()
:將字符串轉(zhuǎn)換為小寫。 -
trim()
:去除字符串兩端的空格。 -
replace(CharSequence target, CharSequence replacement)
:將指定的目標(biāo)字符串替換為指定的替換字符串。StringBuilder常用方法:
-
append(String str)
:將指定字符串追加到當(dāng)前字符串的末尾。 -
insert(int offset, String str)
:在指定的偏移位置插入指定的字符串。 -
delete(int start, int end)
:刪除從指定開始索引到指定結(jié)束索引之間的字符。 -
reverse()
:反轉(zhuǎn)當(dāng)前字符串。 -
replace(int start, int end, String str)
:將指定范圍內(nèi)的字符替換為指定的字符串。 -
length()
:返回字符串的長度。 -
charAt(int index)
:返回指定索引位置的字符。 -
substring(int start)
:返回從指定索引開始到字符串末尾的子字符串。 -
substring(int start, int end)
:返回從指定索引開始到指定索引結(jié)束的子字符串。 -
toString()
:將StringBuilder
對象轉(zhuǎn)換為普通的字符串。這些方法只是
String
和StringBuilder
類中的一部分,它們提供了豐富的功能來處理字符串。你可以根據(jù)具體的需求選擇適合的方法來操作字符串。
疑難點:
在你給出的代碼中:
//1. 創(chuàng)建一個StringBuilder對象
StringBuilder sb = new StringBuilder("abc");
//2. 反轉(zhuǎn)
StringBuilder s = sb.reverse();
//3. 轉(zhuǎn)化為String
String str = s.toString();
這里沒有錯誤,讓我解釋一下為什么這樣是有效的:
-
首先,你創(chuàng)建了一個
StringBuilder
對象sb
并用字符串"abc"
初始化它。 -
然后,你調(diào)用了
sb
的reverse()
方法。reverse()
方法是StringBuilder
類的一個實例方法,它的作用是將StringBuilder
對象內(nèi)部的字符序列反轉(zhuǎn)。這個方法返回的是反轉(zhuǎn)后的StringBuilder
對象本身的引用,即this
引用。因此,s
和sb
實際上是引用同一個對象。 -
接著,你調(diào)用了
s.toString()
方法。由于s
是StringBuilder
類型的一個引用,它指向的是一個有效的StringBuilder
對象(即最初的sb
對象,現(xiàn)在字符序列已被反轉(zhuǎn)),因此調(diào)用toString()
方法是合法的。toString()
方法將StringBuilder
對象內(nèi)部的字符序列轉(zhuǎn)換為一個新的String
對象。
在Java中,變量名(如 s
和 sb
)只是對象的引用,它們不是對象本身。在這段代碼中,s
和 sb
都是指向同一個 StringBuilder
對象的引用。當(dāng)你對這個對象調(diào)用方法時,不管是通過哪個引用調(diào)用的,效果都是相同的。因此,s.toString()
是完全有效的,它會調(diào)用那個共享對象的 toString()
方法,并不會產(chǎn)生錯誤。
在 Java 中,System.out.println()
方法用于將內(nèi)容打印到控制臺。當(dāng)你傳遞一個表達式作為參數(shù)時,Java 會將其解析為一個字符串并進行打印。
在你的代碼中,len + sb
是一個表達式,其中 len
是一個整數(shù),sb
是一個 StringBuilder
對象。如果你直接將這個表達式作為參數(shù)傳遞給 System.out.println()
,Java 會將其解析為一個整數(shù)和一個 StringBuilder
對象的相加操作,而不是將它們轉(zhuǎn)換成字符串進行拼接。
為了將表達式轉(zhuǎn)換為字符串拼接,你可以在表達式前面添加一個空字符串 ""
,這會觸發(fā) Java 將整個表達式轉(zhuǎn)換為字符串的操作。這樣,len + sb
就會被解析為字符串拼接,而不是數(shù)值相加。
因此,正確的寫法是 System.out.println("" + len + sb);
,其中空字符串 ""
會將整個表達式轉(zhuǎn)換為字符串拼接。這樣就可以將 len
和 sb
轉(zhuǎn)換為字符串,并進行拼接輸出到控制臺。
StringJoiner
在Java中,StringJoiner
是一個用于連接字符串的實用類。它可以方便地將多個字符串連接成一個字符串,并可以在字符串之間指定分隔符。
StringJoiner
類提供了以下構(gòu)造方法:
-
StringJoiner(CharSequence delimiter)
: 創(chuàng)建一個新的StringJoiner
對象,使用指定的分隔符。 -
StringJoiner(CharSequence delimiter, CharSequence prefix, CharSequence suffix)
: 創(chuàng)建一個新的StringJoiner
對象,使用指定的分隔符、前綴和后綴。
StringJoiner
類的常用方法包括:
-
StringJoiner add(CharSequence element)
: 向當(dāng)前StringJoiner
對象添加一個元素。 -
StringJoiner merge(StringJoiner other)
: 將另一個StringJoiner
對象中的元素合并到當(dāng)前對象中。 -
String toString()
: 返回連接后的字符串。
下面是一個示例,展示了如何使用 StringJoiner
類將多個字符串連接成一個字符串:
import java.util.StringJoiner;
public class Example {
public static void main(String[] args) {
StringJoiner stringJoiner = new StringJoiner(", "); // 使用逗號和空格作為分隔符
stringJoiner.add("Apple");
stringJoiner.add("Banana");
stringJoiner.add("Orange");
String result = stringJoiner.toString();
System.out.println(result); // 輸出: Apple, Banana, Orange
}
}
在上述示例中,我們創(chuàng)建了一個 StringJoiner
對象 stringJoiner
,指定了分隔符為逗號和空格。然后,我們使用 add()
方法向 stringJoiner
添加了三個字符串。最后,通過調(diào)用 toString()
方法,我們得到了連接后的字符串,并將其打印出來。
StringJoiner
類在處理字符串連接時非常方便,特別是在需要拼接多個字符串并指定分隔符的情況下。它可以避免手動處理分隔符和邊界情況的麻煩,并提供了簡潔的 API。
字符串相關(guān)類的底層原理
在Java中,字符串相關(guān)的類主要有String
、StringBuilder
和StringBuffer
。它們在內(nèi)存中存儲和處理字符串的方式略有不同。
-
String
類:-
String
類是不可變的,即創(chuàng)建后不能被修改。每次對字符串進行修改(如拼接、替換等),都會創(chuàng)建一個新的字符串對象。 - 字符串常量池(String Pool)是
String
類的一個重要特性。當(dāng)創(chuàng)建字符串字面量時,JVM會首先檢查字符串常量池中是否存在相同內(nèi)容的字符串,如果存在,則直接返回常量池中的引用,而不會創(chuàng)建新的對象。 -
String
對象在內(nèi)存中以連續(xù)的字符數(shù)組(char[]
)形式存儲。
-
-
StringBuilder
類:-
StringBuilder
類是可變的,可以進行字符串的拼接、插入、刪除等操作,而不會創(chuàng)建新的對象。 -
StringBuilder
使用一個可調(diào)整大小的字符數(shù)組(char[]
)來存儲字符串內(nèi)容,當(dāng)需要修改字符串時,會直接在字符數(shù)組上進行操作。 -
StringBuilder
的操作是非線程安全的,適用于單線程環(huán)境。
-
-
StringBuffer
類:-
StringBuffer
類與StringBuilder
類類似,也是可變的,可以進行字符串的修改操作。 -
StringBuffer
也使用一個可調(diào)整大小的字符數(shù)組(char[]
)來存儲字符串內(nèi)容,但與StringBuilder
不同的是,StringBuffer
的操作是線程安全的。 -
StringBuffer
的方法使用了synchronized
關(guān)鍵字來保證線程安全,因此在多線程環(huán)境中推薦使用StringBuffer
。
-
總體來說,String
類適用于字符串不經(jīng)常修改的場景,而StringBuilder
和StringBuffer
適用于需要頻繁修改字符串的場景。StringBuilder
和StringBuffer
的底層實現(xiàn)都是通過字符數(shù)組來存儲和操作字符串,不同之處在于線程安全性。
中文的存儲原理
在 Java 中,中文字符是使用 Unicode 編碼進行存儲的。Unicode 是一種字符集,它為世界上幾乎所有的字符都分配了一個唯一的標(biāo)識符,包括中文字符。
Unicode 為每個字符分配了一個唯一的代碼點,用十六進制表示。例如,中文字符 "中" 的 Unicode 編碼是 \u4E2D
,其中 \u
表示后面跟著的是一個 Unicode 編碼。
Java 中的字符串類型 String
是基于 Unicode 編碼的,它可以存儲任意 Unicode 字符,包括中文字符。當(dāng)你在 Java 中創(chuàng)建一個字符串時,你可以直接使用中文字符,例如:
String chinese = "中文字符串";
在內(nèi)存中,Java 使用 UTF-16 編碼來表示字符串。UTF-16 是一種可變長度的編碼方案,它可以用 16 位編碼表示大部分常見字符,但對于一些罕見的字符,可能需要使用兩個 16 位編碼來表示。
Java 提供了一些方法來處理字符串和字符的 Unicode 編碼。例如,可以使用 charAt()
方法獲取字符串中指定位置的字符,然后使用 char
類型來表示該字符的 Unicode 編碼。還可以使用 getBytes()
方法將字符串轉(zhuǎn)換為字節(jié)數(shù)組,其中每個字符都使用 UTF-8 編碼進行存儲。
需要注意的是,Java 中的字符類型 char
是使用 UTF-16 編碼的,它占用 16 位(2 字節(jié))的存儲空間。對于大部分常見的字符,一個 char
可以存儲一個字符,但對于一些罕見的字符或輔助字符,可能需要使用兩個 char
來表示一個字符。
總結(jié)來說,Java 使用 Unicode 編碼來存儲中文字符和其他字符,它提供了一種統(tǒng)一的方式來表示世界上幾乎所有的字符。
String的常見的構(gòu)造方法
在Java中,String
類有多種構(gòu)造方法,可以用來以不同的方式創(chuàng)建字符串。以下是一些常見的 String
構(gòu)造方法:
-
無參構(gòu)造方法:創(chuàng)建一個空的字符串。
String s = new String();
-
從數(shù)組構(gòu)造:從字符數(shù)組中創(chuàng)建字符串。
char[] chars = {'H', 'e', 'l', 'l', 'o'}; String s = new String(chars);
-
從數(shù)組的子集構(gòu)造:從字符數(shù)組的子集中創(chuàng)建字符串。
char[] chars = {'H', 'e', 'l', 'l', 'o'}; String s = new String(chars, 1, 3); // "ell"
-
從另一個字符串構(gòu)造:復(fù)制另一個字符串的內(nèi)容。
String original = "Hello"; String s = new String(original);
-
從字節(jié)數(shù)組構(gòu)造:使用平臺默認的字符集,將字節(jié)數(shù)組轉(zhuǎn)換為字符串。
byte[] bytes = {72, 101, 108, 108, 111}; String s = new String(bytes);
-
從字節(jié)數(shù)組的子集構(gòu)造:使用平臺默認的字符集,將字節(jié)數(shù)組的子集轉(zhuǎn)換為字符串。
byte[] bytes = {72, 101, 108, 108, 111}; String s = new String(bytes, 1, 3); // "ell"
-
指定字符集的字節(jié)數(shù)組構(gòu)造:指定字符集將字節(jié)數(shù)組轉(zhuǎn)換為字符串。
byte[] bytes = {72, 101, 108, 108, 111}; String s = new String(bytes, Charset.forName("UTF-8"));
-
指定字符集的字節(jié)數(shù)組的子集構(gòu)造:指定字符集將字節(jié)數(shù)組的子集轉(zhuǎn)換為字符串。
byte[] bytes = {72, 101, 108, 108, 111}; String s = new String(bytes, 1, 3, Charset.forName("UTF-8")); // "ell"
-
從
StringBuilder
構(gòu)造:從一個StringBuilder
對象中創(chuàng)建字符串。StringBuilder sb = new StringBuilder("Hello"); String s = new String(sb);
-
從
StringBuffer
構(gòu)造:從一個StringBuffer
對象中創(chuàng)建字符串。StringBuffer sb = new StringBuffer("Hello"); String s = new String(sb);
-
從
CharSequence
接口構(gòu)造:從實現(xiàn)了CharSequence
接口的任意類型(如String
,StringBuilder
,StringBuffer
等)創(chuàng)建字符串。文章來源:http://www.zghlxwxcb.cn/news/detail-846135.htmlCharSequence cs = "Hello"; String s = new String(cs);
注意:在實際編程中,直接使用字符串字面量(如 String s = "Hello";
)是創(chuàng)建字符串的最常見方式,因為這種方式簡潔且性能良好。Java虛擬機會在字符串常量池中維護這些字面量,以便重用。直接使用構(gòu)造方法創(chuàng)建字符串的情況較少,通常只在需要從不同數(shù)據(jù)源(如數(shù)組或緩沖區(qū))創(chuàng)建字符串時才會用到。文章來源地址http://www.zghlxwxcb.cn/news/detail-846135.html
到了這里,關(guān)于Java的字符串的基礎(chǔ)知識(必看)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!