深入理解Java中的String(示例詳解)
前言
在Java中,String類是一個(gè)非常重要的內(nèi)置類,用于處理字符串?dāng)?shù)據(jù)。字符串是不可變的(immutable),這意味著一旦創(chuàng)建,字符串的內(nèi)容不能被修改。作為Java中最為基礎(chǔ)和常用的類之一,String類在內(nèi)存管理、線程安全、性能優(yōu)化等方面都有著獨(dú)特的設(shè)計(jì)和實(shí)現(xiàn)。本文將詳細(xì)介紹Java中String類的特點(diǎn)、用途、主要方法以及常見用法,并通過代碼示例展示如何在Java中創(chuàng)建、操作和使用String類。
1. String類的特點(diǎn)
1.1 不可變性
String對(duì)象一旦創(chuàng)建,其內(nèi)容就不能被更改。這種不可變性是通過final關(guān)鍵字修飾字符數(shù)組value來實(shí)現(xiàn)的。String類中沒有提供修改字符數(shù)組的方法,任何對(duì)字符串的修改操作(如拼接、替換等)都會(huì)創(chuàng)建一個(gè)新的String對(duì)象。
String str1 = "Hello"; String str2 = str1.concat(" World"); // 創(chuàng)建一個(gè)新的字符串對(duì)象"Hello World" System.out.println(str1); // 輸出: Hello System.out.println(str2); // 輸出: Hello World
不可變性帶來了多個(gè)好處:
- 安全性:在多線程環(huán)境中,多個(gè)線程可以安全地共享同一個(gè)字符串對(duì)象,而不用擔(dān)心數(shù)據(jù)被修改。
- 內(nèi)存效率:不可變字符串可以被共享。當(dāng)在常量池中創(chuàng)建一個(gè)字符串字面量時(shí),后續(xù)對(duì)同一內(nèi)容的引用會(huì)直接指向常量池中的對(duì)象,而不是創(chuàng)建新的對(duì)象,從而減少了內(nèi)存消耗。
- 哈希碼緩存:由于字符串不可變,它們的哈希碼只計(jì)算一次,并可以被緩存。這使得字符串在作為哈希表的鍵時(shí)更加高效,因?yàn)椴恍枰诿看尾檎視r(shí)重新計(jì)算哈希值。
1.2 字符串常量池
字符串常量池是Java中一個(gè)特殊的內(nèi)存區(qū)域,用于存儲(chǔ)字符串字面量和一些常量字符串。當(dāng)使用字面量方式創(chuàng)建String對(duì)象時(shí),JVM會(huì)首先檢查字符串常量池中是否已經(jīng)存在相同內(nèi)容的字符串對(duì)象。如果存在,則直接返回常量池中該字符串對(duì)象的引用;如果不存在,則在常量池中創(chuàng)建一個(gè)新的字符串對(duì)象,并返回其引用。
String str1 = "Hello"; String str2 = "Hello"; System.out.println(str1 == str2); // 輸出: true,str1和str2引用的是同一個(gè)字符串對(duì)象
通過intern()方法,可以手動(dòng)將一個(gè)String對(duì)象放入字符串常量池中。
String str1 = new String("Hello"); String str2 = str1.intern(); String str3 = "Hello"; System.out.println(str2 == str3); // 輸出: true,str2和str3引用的是同一個(gè)字符串對(duì)象
1.3 內(nèi)存結(jié)構(gòu)
String對(duì)象在內(nèi)存中的存儲(chǔ)結(jié)構(gòu)主要包括字符數(shù)組value、哈希碼hash以及偏移量offset(在JDK 9及以后版本中,如果字符串內(nèi)容都在Latin-1字符集內(nèi),則使用byte數(shù)組存儲(chǔ),并結(jié)合編碼標(biāo)識(shí)來區(qū)分)。
- 字符數(shù)組value:用于存儲(chǔ)字符串的字符序列。在JDK 9之前,使用的是UTF-16編碼的字符數(shù)組;在JDK 9及以后版本中,如果字符串內(nèi)容都在Latin-1字符集內(nèi),則使用byte數(shù)組存儲(chǔ)。
- 哈希碼hash:用于緩存字符串的哈希碼,以避免在每次調(diào)用hashCode()方法時(shí)重新計(jì)算。
- 偏移量offset(在JDK 9及以后版本中):用于標(biāo)識(shí)字符串在byte數(shù)組中的起始位置(如果字符串使用byte數(shù)組存儲(chǔ))。
1.4 JDK版本更新對(duì)String類的影響
隨著JDK版本的更新,String類的底層設(shè)計(jì)和優(yōu)化也在不斷發(fā)展。
- JDK 6:字符串常量池位于永久代(方法區(qū))中,存儲(chǔ)的是對(duì)象本身。
- JDK 7:將常量池從永久代移到了堆內(nèi)存中,存儲(chǔ)的是對(duì)象的引用。
- JDK 8:引入了元空間(Metaspace)來取代永久代,優(yōu)化了字符串的創(chuàng)建和intern()方法的行為。
- JDK 9:對(duì)String類進(jìn)行了重大的底層優(yōu)化,改用byte數(shù)組存儲(chǔ)字符串?dāng)?shù)據(jù)(如果字符串內(nèi)容都在Latin-1字符集內(nèi)),并引入了coder字段和COMPACT_STRINGS屬性來控制字符串的緊湊存儲(chǔ)功能。
2. String類的用途
2.1 表示文本數(shù)據(jù)
字符串是計(jì)算機(jī)科學(xué)中用來表示文本數(shù)據(jù)的標(biāo)準(zhǔn)方式。在Java中,字符串常用于表示用戶的姓名、地址等個(gè)人信息,以及程序中的各種文本信息。
2.2 處理文本數(shù)據(jù)
Java提供了豐富的內(nèi)置函數(shù)和方法,使開發(fā)者能夠輕松地進(jìn)行文本數(shù)據(jù)的處理。例如,可以使用String類的各種方法來查找子字符串、替換字符、分割字符串等。
2.3 內(nèi)存管理和性能優(yōu)化
通過字符串常量池和不可變性設(shè)計(jì),String類在內(nèi)存管理和性能優(yōu)化方面表現(xiàn)出色。它減少了內(nèi)存中的重復(fù)字符串存儲(chǔ),提高了內(nèi)存利用率和訪問效率,并允許JVM對(duì)字符串進(jìn)行緩存和重用,減少了創(chuàng)建新對(duì)象的開銷。
3. String類的主要方法
3.1 創(chuàng)建字符串
3.1.1 直接賦值
String str = "Hello, World!";
這種方式創(chuàng)建的字符串對(duì)象會(huì)被放入字符串常量池中。
3.1.2 使用new關(guān)鍵字
String str = new String("Hello, World!");
這種方式會(huì)在堆內(nèi)存中創(chuàng)建一個(gè)新的String對(duì)象,而不會(huì)放入字符串常量池中(除非通過intern()方法手動(dòng)放入)。
3.1.3 字符數(shù)組轉(zhuǎn)String
char[] array = {'a', 'b', 'c'}; String str = new String(array);
3.2 字符串比較
3.2.1 == 比較
String str1 = "Hello"; String str2 = "Hello"; String str3 = new String("Hello"); System.out.println(str1 == str2); // 輸出: true,str1和str2引用的是同一個(gè)字符串對(duì)象 System.out.println(str1 == str3); // 輸出: false,str1和str3引用的是不同的字符串對(duì)象
== 比較的是字符串對(duì)象的引用是否相同。
3.2.2 equals方法
System.out.println(str1.equals(str3)); // 輸出: true,str1和str3的內(nèi)容相同
equals方法比較的是字符串對(duì)象的內(nèi)容是否相同。
3.2.3 compareTo方法
String str4 = "World"; System.out.println(str1.compareTo(str4)); // 輸出: -11,按照字典順序,"Hello"小于"World"
compareTo方法按字典順序比較兩個(gè)字符串的大小關(guān)系,返回值為int類型。
3.2.4 compareToIgnoreCase方法
System.out.println(str1.compareToIgnoreCase(str4)); // 輸出: -11,忽略大小寫比較
compareToIgnoreCase方法與compareTo方法類似,但在比較時(shí)忽略字母大小寫。
3.3 獲取長(zhǎng)度
String str = "Hello, World!"; int length = str.length(); // 返回字符串的長(zhǎng)度 System.out.println(length); // 輸出: 13
3.4 字符串查找
3.4.1 charAt方法
char ch = str.charAt(7); // 返回指定索引位置上的字符 System.out.println(ch); // 輸出: W
charAt方法返回指定索引位置上的字符,索引范圍從0開始。
3.4.2 indexOf方法
int index = str.indexOf("World"); // 返回指定子字符串第一次出現(xiàn)的位置 System.out.println(index); // 輸出: 7 index = str.indexOf("Java", 8); // 從指定索引開始查找 System.out.println(index); // 輸出: -1,未找到
indexOf方法返回指定子字符串第一次出現(xiàn)的位置,如果未找到則返回-1。
3.4.3 lastIndexOf方法
int lastIndex = str.lastIndexOf("o"); // 返回指定字符最后一次出現(xiàn)的位置 System.out.println(lastIndex); // 輸出: 8 lastIndex = str.lastIndexOf("o", 7); // 從指定索引開始反向搜索 System.out.println(lastIndex); // 輸出: 4
lastIndexOf方法返回指定字符或子字符串最后一次出現(xiàn)的位置,如果未找到則返回-1。
3.4.4 contains方法
boolean containsHello = str.contains("Hello"); // 判斷字符串是否包含指定的字符序列 System.out.println(containsHello); // 輸出: true
contains方法用于判斷字符串是否包含指定的字符序列。
3.5 子字符串
3.5.1 substring方法
String subStr = str.substring(7, 12); // 返回從beginIndex開始到endIndex-1的子字符串 System.out.println(subStr); // 輸出: World
substring方法返回從beginIndex開始到endIndex-1的子字符串。
3.6 字符串替換
3.6.1 replace方法
String replacedStr = str.replace("World", "Java"); // 替換字符串中的字符 System.out.println(replacedStr); // 輸出: Hello, Java!
replace方法用于替換字符串中的字符或子字符串。
3.6.2 replaceAll方法
String replacedAllStr = str.replaceAll("o", "0"); // 使用正則表達(dá)式替換字符串中的內(nèi)容 System.out.println(replacedAllStr); // 輸出: Hell0, W0rld!
replaceAll方法使用正則表達(dá)式替換字符串中的所有匹配項(xiàng)。
3.6.3 replaceFirst方法
String replacedFirstStr = str.replaceFirst("o", "0"); // 替換字符串中的第一個(gè)匹配項(xiàng) System.out.println(replacedFirstStr); // 輸出: Hello, W0rld!
replaceFirst方法替換字符串中的第一個(gè)匹配項(xiàng)。
3.7 大小寫轉(zhuǎn)換
3.7.1 toLowerCase方法
String lowerStr = str.toLowerCase(); // 將字符串轉(zhuǎn)換為小寫 System.out.println(lowerStr); // 輸出: hello, world!
toLowerCase方法將字符串轉(zhuǎn)換為小寫。
3.7.2 toUpperCase方法
String upperStr = str.toUpperCase(); // 將字符串轉(zhuǎn)換為大寫 System.out.println(upperStr); // 輸出: HELLO, WORLD!
toUpperCase方法將字符串轉(zhuǎn)換為大寫。
3.8 去除字符串首尾空格
String trimmedStr = str.trim(); // 去除字符串兩端的空白字符 System.out.println(trimmedStr); // 輸出: Hello, World!(假設(shè)原字符串兩端沒有空格)
trim方法用于去除字符串兩端的空白字符(包括空格、制表符、換行符等)。
3.9 字符串拆分
String[] splitStrs = str.split(", "); // 根據(jù)正則表達(dá)式拆分字符串 for (String s : splitStrs) { System.out.println(s); } // 輸出: // Hello // World!
split方法根據(jù)給定的正則表達(dá)式拆分字符串,并返回一個(gè)字符串?dāng)?shù)組。
3.10 字符串連接
3.10.1 使用+操作符
String concatenatedStr = "Hello" + " " + "World!"; // 使用+操作符連接字符串 System.out.println(concatenatedStr); // 輸出: Hello World!
在編譯時(shí),Java會(huì)將多個(gè)字符串字面量的拼接優(yōu)化為一個(gè)StringBuilder的append操作。
3.10.2 使用StringBuilder或StringBuffer
StringBuilder sb = new StringBuilder(); sb.append("Hello").append(" ").append("World!"); String concatenatedStr = sb.toString(); System.out.println(concatenatedStr); // 輸出: Hello World!
StringBuilder和StringBuffer都提供了可變字符串的操作,但StringBuilder是非線程安全的,而StringBuffer是線程安全的。在單線程環(huán)境中,建議使用StringBuilder以提高性能。
3.11 其他常用方法
3.11.1 startsWith方法
boolean startsWithHello = str.startsWith("Hello"); // 判斷字符串是否以指定的前綴開始 System.out.println(startsWithHello); // 輸出: true
startsWith方法用于判斷字符串是否以指定的前綴開始。
3.11.2 endsWith方法
boolean endsWithExclamation = str.endsWith("!"); // 判斷字符串是否以指定的后綴結(jié)束 System.out.println(endsWithExclamation); // 輸出: true
endsWith方法用于判斷字符串是否以指定的后綴結(jié)束。
3.11.3 toCharArray方法
char[] charArray = str.toCharArray(); // 將字符串轉(zhuǎn)換為字符數(shù)組 for (char c : charArray) { System.out.print(c); } // 輸出: Hello, World!
toCharArray方法將字符串轉(zhuǎn)換為字符數(shù)組。
3.11.4 split(String regex, int limit)方法
String[] splitStrsWithLimit = str.split(", ", 2); // 根據(jù)正則表達(dá)式拆分字符串,并限制拆分次數(shù) for (String s : splitStrsWithLimit) { System.out.println(s); } // 輸出: // Hello // World!
split(String regex, int limit)方法根據(jù)給定的正則表達(dá)式拆分字符串,并限制拆分的次數(shù)。
4. String類的常見用法
4.1 字符串拼接
在Java中,字符串拼接是一個(gè)常見的操作。由于String的不可變性,直接使用+操作符進(jìn)行字符串拼接可能會(huì)導(dǎo)致性能問題(特別是在循環(huán)中多次拼接字符串時(shí))。因此,建議使用StringBuilder或StringBuffer來進(jìn)行字符串拼接。
// 使用+操作符進(jìn)行字符串拼接(不推薦在循環(huán)中使用) String result = ""; for (int i = 0; i < 1000; i++) { result += "Hello "; } System.out.println(result); // 使用StringBuilder進(jìn)行字符串拼接(推薦) StringBuilder sb = new StringBuilder(); for (int i = 0; i < 1000; i++) { sb.append("Hello "); } String resultWithStringBuilder = sb.toString(); System.out.println(resultWithStringBuilder);
4.2 字符串比較
在Java中,字符串比較通常使用equals方法而不是 ==
操作符。因?yàn)?code>==操作符比較的是字符串對(duì)象的引用是否相同,而equals方法比較的是字符串對(duì)象的內(nèi)容是否相同。
String str1 = "Hello"; String str2 = new String("Hello"); System.out.println(str1 == str2); // 輸出: false,str1和str2引用的是不同的字符串對(duì)象 System.out.println(str1.equals(str2)); // 輸出: true,str1和str2的內(nèi)容相同
4.3 字符串查找和替換
在文本處理中,經(jīng)常需要查找子字符串或替換字符串中的某些字符。String類提供了豐富的方法來支持這些操作。
String text = "Hello, welcome to the world of Java!"; // 查找子字符串 int index = text.indexOf("welcome"); System.out.println("Index of 'welcome': " + index); // 輸出: 7 // 替換字符串中的字符 String replacedText = text.replace("Java", "Programming"); System.out.println(replacedText); // 輸出: Hello, welcome to the world of Programming!
4.4 字符串拆分
在處理CSV文件或解析復(fù)雜字符串時(shí),經(jīng)常需要將字符串拆分為多個(gè)部分。String類的split方法提供了方便的方式來實(shí)現(xiàn)這一點(diǎn)。
String csvLine = "name,age,city"; String[] fields = csvLine.split(","); for (String field : fields) { System.out.println(field); } // 輸出: // name // age // city
4.5 字符串格式化
在輸出格式化字符串時(shí),可以使用String.format方法或Formatter類。
String name = "Alice"; int age = 30; String formattedString = String.format("Name: %s, Age: %d", name, age); System.out.println(formattedString); // 輸出: Name: Alice, Age: 30
總結(jié)
Java中的String類是一個(gè)重要的內(nèi)置類,用于處理字符串?dāng)?shù)據(jù)。其特點(diǎn)包括不可變性、字符串常量池、特定的內(nèi)存結(jié)構(gòu)以及隨JDK版本更新的優(yōu)化。String類廣泛用于表示和處理文本數(shù)據(jù),并在內(nèi)存管理和性能優(yōu)化方面表現(xiàn)出色。主要方法包括創(chuàng)建字符串、字符串比較、獲取長(zhǎng)度、字符串查找、子字符串操作、字符串替換、大小寫轉(zhuǎn)換、去除首尾空格、字符串拆分和連接等。常見用法涉及字符串拼接、比較、查找和替換、拆分以及格式化。通過合理使用String類的方法,可以有效處理文本數(shù)據(jù)并優(yōu)化程序性能。
到此這篇關(guān)于深入理解Java中的String的文章就介紹到這了,更多相關(guān)Java中String內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- JSON.toJSONString()方法在Java中的使用方法及應(yīng)用場(chǎng)景
- Java中的String不可變性實(shí)現(xiàn)
- Java中的StringTokenizer實(shí)現(xiàn)字符串切割詳解
- Java中的String、StringBuilder、StringBuffer三者的區(qū)別詳解
- Java的String類中的startsWith方法和endsWith方法示例詳解
- Java中的StringJoiner類使用示例深入詳解
- Java中的StringBuilder()常見方法詳解
- java8中的List<String>轉(zhuǎn)List<Integer>的實(shí)例代碼
- Java中如何取出String字符串括號(hào)中的內(nèi)容
- Java中的StringUtils引入及使用示例教程
相關(guān)文章
Spring AOP有多少個(gè)通知以及它們的執(zhí)行順序介紹
這篇文章主要介紹了Spring AOP有多少個(gè)通知以及它們的執(zhí)行順序,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-11-11SpringBoot中使用Swagger的超簡(jiǎn)單方法
大家一致認(rèn)為springBoot使用swagger太麻煩了,每次都需要編寫config,今天小編告訴大家一種超簡(jiǎn)單配置方法,教大家如何整合swagger,感興趣的朋友跟隨小編一起看看吧2021-07-07javaSystem.out.println()輸出byte[]、char[]異常的問題詳析
這篇文章主要給大家介紹了關(guān)于javaSystem.out.println()輸出byte[]、char[]異常問題的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起看看啊2019-01-01java實(shí)現(xiàn)解析Cron時(shí)間表達(dá)式為中文描述
這篇文章主要為大家詳細(xì)介紹了java如何實(shí)現(xiàn)解析Cron時(shí)間表達(dá)式為中文描述,文中的示例代碼講解詳細(xì),具有一定的學(xué)習(xí)價(jià)值,感興趣的小伙伴可以了解下2023-11-11java基于線程池和反射機(jī)制實(shí)現(xiàn)定時(shí)任務(wù)完整實(shí)例
這篇文章主要介紹了java基于線程池和反射機(jī)制實(shí)現(xiàn)定時(shí)任務(wù)的方法,以完整實(shí)例形式較為詳細(xì)的分析了Java定時(shí)任務(wù)的功能原理與實(shí)現(xiàn)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-11-11Java編程synchronized與lock的區(qū)別【推薦】
互聯(lián)網(wǎng)信息泛濫環(huán)境下少有的良心之作!如果您想對(duì)Java編程synchronized與lock的區(qū)別有所了解,這篇文章絕對(duì)值得!分享給大家,供需要的朋友參考。不說了,我先學(xué)習(xí)去了。2017-10-10關(guān)于Spring項(xiàng)目對(duì)JDBC的支持與基本使用詳解
這段時(shí)間一直在觀看Spring框架,所以下面這篇文章主要給大家介紹了關(guān)于Spring項(xiàng)目對(duì)JDBC的支持與基本使用的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-11-11