Java中關于String StringBuffer StringBuilder特性深度解析
1.String
String類:字符串是常量,使用一對""引起來表示。他們的值在創(chuàng)建之后不能修改。
1.String聲明為final的,不可被繼承
2.String實現(xiàn)了Serializable接口,表示字符串時支持序列化的。
實現(xiàn)了Comparable接口:表示String可以比較大小
3.String內(nèi)部定義了final char[] value用于存儲字符串數(shù)據(jù)
4.String:代表不可變的字符序列。簡稱:不可變性
體現(xiàn):
1.當對字符串重新賦值時,需要重寫指定內(nèi)存區(qū)域賦值,不能使用原有的value進行賦值
2.當對現(xiàn)有的字符串進行連接( + )操作時,也需要重寫指定內(nèi)存區(qū)域賦值,不能使用原有的 value進行賦值
3.當調(diào)用String的replace()方法修改指定字符或字符串時,也需要重新指定內(nèi)存區(qū)域賦值,不能使用原有的value進行賦值
5.通過字面量的方式(區(qū)別于new)給一個字符串賦值,此時的字符串值聲明在字符串常量池中。
6.字符串常量池是不會存儲相同內(nèi)容的字符串的。
public void test1(){ //體現(xiàn)1 String s1 = "abc";//字面量的定義方式 String s2 = "abc"; s1 = "hello"; System.out.println(s1 == s2);//比較s1和s2的地址值 System.out.println(s1);//hello System.out.println(s2);//abc System.out.println("********************************"); //體現(xiàn)2 String s3 = "abc"; s3 += "def"; System.out.println(s3);//abcdef System.out.println(s2);//abc System.out.println("***********************************"); //體現(xiàn)3 String s4 = "abc"; String s5 = s4.replace('a','m'); System.out.println(s4);//abc System.out.println(s5);//mbc }
String的實例化方式:
方式一:通過字面量定義的方式
方式二:通過new + 構(gòu)造器的方式
面試題:String s = new String("abc")的方式創(chuàng)建對象,在內(nèi)存中創(chuàng)建了幾個對象?
兩個:一個是堆空間中new結(jié)構(gòu),另一個是char[]對應的常量池中的數(shù)據(jù):"abc"
public void Test2(){ //通過字面量定義的方式:此時的s1和s2的數(shù)據(jù)javaEE聲明在方法區(qū)中的字符串常量池中。 String s1 = "javaEE"; String s2 = "javaEE"; //通過new + 構(gòu)造器的方式:此時的s3和s4保存的地址值,是數(shù)據(jù)在堆空間中開辟空間以后對應的地址值 String s3 = new String("javaEE"); String s4 = new String("javaEE"); System.out.println(s1 == s2);//true System.out.println(s1 == s3);//false System.out.println(s1 == s4);//false System.out.println(s3 == s4);//false System.out.println("******************************************"); Person p1 = new Person("Tom",12); Person p2 = new Person("Tom",12); System.out.println(p1.name.equals(p2.name));//true System.out.println(p1.name == p2.name);//true//通過字面量的方式賦值,所以是true!!!!!!!!!!!! }
public void Test3(){ String s1 = "javaEE"; String s2 = "hadoop"; String s3 = "javaEEhadoop"; String s4 = "javaEE" + "hadoop"; String s5 = s1 + "hadoop"; String s6 = "javaEE" + s2; String s7 = s1 + s2; System.out.println(s3 == s4);//true System.out.println(s3 == s5);//false//字面值方式的儲存在常量池,有變量的在堆里 System.out.println(s3 == s6);//false System.out.println(s3 == s7);//false System.out.println(s5 == s6);//false System.out.println(s5 == s7);//false System.out.println(s6 == s7);//false String s8 = s5.intern();//返回值得到的s8使用的常量池已經(jīng)存在的"javaEEhadoop" System.out.println(s3 == s8);//true } @Test public void test4(){ String s1 = "javaEEhadoop"; String s2 = "javaEE"; String s3 = s2 + "hadoop"; System.out.println(s1 == s3);//false final String s4 = "javaEE";//s4:常量 String s5 = s4 + "hadoop"; System.out.println(s1 == s5);//true }
結(jié)論:
1.常量與常量的拼接結(jié)果在常量池。且常量池中不會存在相同內(nèi)容的常量。
2.只要其中有一個是變量,結(jié)果就在堆中。
3.如果拼接的結(jié)果調(diào)用intern()方法,返回值就在常量池中
一道有深度的面試題
public class StringTest { String str = new String("good"); char[] ch = {'t','e','s','t'}; public void change(String str,char ch[]){ str = "test ok"; ch[0] = 'b'; } public static void main(String[] args) { StringTest ex = new StringTest(); ex.change(ex.str,ex.ch); System.out.println(ex.str);//good System.out.println(ex.ch);//best } }
解析:
1.涉及的知識:
關于變量的賦值:如果變量是基本數(shù)據(jù)類型,此時賦值的是變量所保存的數(shù)據(jù)值。
如果變量是引用數(shù)據(jù)類型,此時賦值的是變量所保存的數(shù)據(jù)的地址值。
Java中的方法的值傳遞機制:所謂的值傳遞,就是將實參值的副本傳入方法里,而參數(shù)本身不受影響。
2.面試題的解析:因為傳值過程中,傳給形參的是地址值,而通過String試圖修改實參是行不通的,因為String有不可變性。而數(shù)組的內(nèi)容是可以修改的,通過形參修改堆空間中的數(shù)組中的內(nèi)容,實參也會改變,因為形參和實參指向?qū)臻g中的同一個內(nèi)容
String的常用方法及其測試
public void test1(){ String s1 = "HelloWorld"; System.out.println(s1.length());//10 System.out.println(s1.charAt(0));//H System.out.println(s1.isEmpty());//false String s2 = s1.toLowerCase(); System.out.println(s1);//HelloWorld//s1是不可變的,仍然為原來的字符串 System.out.println(s2);//helloworld//改成小寫以后的字符串 String s3 = " he llo world "; String s4 = s3.trim(); System.out.println("-----" + s3 + "-----");//----- he llo world ----- System.out.println("-----" + s4 + "-----");// -----he llo world----- } public void test2(){ String s1 = "HelloWorld"; String s2 = "helloworld"; System.out.println(s1.equals(s2));//false System.out.println(s1.equalsIgnoreCase(s2));//true String s3 = "abc"; String s4 = s3.concat("def"); System.out.println(s4);//abcdef String s5 = "abc"; String s6 = new String("abe"); System.out.println(s5.compareTo(s6));//-2 String s7 = "開關電源適配器"; String s8 = s7.substring(2); System.out.println(s7);//開關電源適配器 System.out.println(s8);//電源適配器 String s9 = s7.substring(2,5); System.out.println(s9);//電源適 }
public void test3(){ String str1 = "helloworld"; boolean b1 = str1.endsWith("rld"); System.out.println(b1);//true boolean b2 = str1.endsWith("He"); System.out.println(b2);//false boolean b3 = str1.startsWith("ll",2); System.out.println(b3);//true String str2 = "wor"; System.out.println(str1.contains(str2));//true System.out.println(str1.indexOf("lol"));//-1 System.out.println(str1.indexOf("lo",5));//-1 String str3 = "hellorworld"; System.out.println(str3.lastIndexOf("or"));//7 System.out.println(str3.lastIndexOf("or",6));//4 }
此方法測試詳見另一篇博客:自動裝箱與自動拆箱
與正則表達式有關的方法的測試
public void test4(){ String str1 = "北京尚硅谷教育北京"; String str2 = str1.replace('北','東'); System.out.println(str1);//北京尚硅谷教育北京 System.out.println(str2);// 東京尚硅谷教育東京 String str3 = str1.replace("北京","上海"); System.out.println(str3);//上海尚硅谷教育上海 String str = "12hello34world5java7891mysql456"; //把字符串中的數(shù)字替換成,,如果結(jié)果中開頭和結(jié)尾有,的話去掉 String string = str.replaceAll("\\d+",",").replaceAll("^,|,$",""); System.out.println(string);//hello,world,java,mysql str = "12345"; //判斷str字符串中是否全部由數(shù)字組成,既由1-n個數(shù)字組成 boolean matches = str.matches("\\d+"); System.out.println(matches);//true String tel = "0571-4534289"; //判斷這是否是一個杭州的固定電話 boolean result = tel.matches("0571-\\d{7,8}"); System.out.println(result);//true str = "hello|world|java"; String[] strs = str.split("\\|"); for(int i = 0;i < strs.length;i++){ System.out.print(strs[i]);//hello world java } }
/* String 與 char[]之間的轉(zhuǎn)換 String --> char[]:調(diào)用String的toCharArray() char[] --> String:調(diào)用String的構(gòu)造器 */ @Test public void test2(){ String str1 = "abc123"; char[] charArray = str1.toCharArray(); for(int i = 0;i < charArray.length;i++){ System.out.println(charArray[i]); } char[] arr = new char[]{'h','e','l','l','o'}; String str2 = new String(arr); System.out.println(str2); }
/* String 與 byte[]之間的轉(zhuǎn)換 編碼:String --> byte[]:調(diào)用String的getBytes() 解碼: byte[] --> String:調(diào)用String的構(gòu)造器 編碼:字符串 --> 字節(jié)(看得懂 --> 看不懂的二進制數(shù)據(jù)) 解碼:編碼的逆過程,字節(jié) --> 字符串 (看不懂的二進制數(shù)據(jù) --> 看的懂) 說明:解碼時,要求解碼使用的字符集必須與編碼時使用的編碼集一致,否則會出現(xiàn)亂碼。 */ @Test public void test3() throws UnsupportedEncodingException { String str1 = "abc123中國"; byte[] bytes = str1.getBytes();//使用默認的字符集,進行轉(zhuǎn)換 System.out.println(Arrays.toString(bytes));//[97, 98, 99, 49, 50, 51, -28, -72, -83, -27, -101, -67] byte[] gbks = str1.getBytes("gbk");//使用了gbk字符集進行編碼 System.out.println(Arrays.toString(gbks));//[97, 98, 99, 49, 50, 51, -42, -48, -71, -6] String str2 = new String(bytes);//使用默認的字符集,進行解碼 System.out.println(str2);//abc123中國 String str3 = new String(gbks);//abc123�й�//亂碼 System.out.println(str3);//出現(xiàn)亂碼,原因:編碼集和解碼集不一致! String str4 = new String(gbks,"gbk"); System.out.println(str4);//abc123中國 }
String、StringBuffer、StringBuilder三者的異同?
String:不可變的字符序列:底層使用char[]存儲
StringBuffer:可變的字符序列:線程安全的,效率低;底層使用char[]存儲
StringBuilder:可變的字符序列:JDK5.0新增的,線程不安全的,效率高;底層使用char[]存儲
源碼分析:
String str = new String();//char[] value = new char[0]; String str1 = new String("abc");//char[] value = new char[]{'a','b','c'}; StringBuffer sb1 = new StringBuffer();//char[] value = new char[16];底層創(chuàng)建了一個長度是16的數(shù)組。 sb1.append('a');//value[0] = 'a'; sb1.append('b');//value[1] = 'b'; StringBuffer sb2 = new StringBuffer("abc");//char[] value = new char["abc".length() + 16];
問題1. System.out.println(sb2.length());//3
問題2. 擴容問題:如果要添加的數(shù)據(jù)底層數(shù)組盛不下了,那就需要擴容底層的數(shù)組。
默認情況下,擴容為原來容量的2倍 + 2,同時將原有的數(shù)組中的元素復制到新的數(shù)組中
指導意義:開發(fā)中建議大家使用:StringBuffer(int capacity)或StringBuilder(int capacity),
傳入預知的參數(shù)長度,可以避免擴容,如果沒涉及到多線程,或者涉及到多線程,但String不是共享數(shù)據(jù)的時候,建議使用StringBuffer,因為效率高
public void test1(){ StringBuffer sb1 = new StringBuffer("abc"); sb1.setCharAt(0,'m'); System.out.println(sb1);//mbc }
對比String、StringBuffer、StringBuilder三者的效率:
從高到低排列:StringBuilder > StringBuffer > String
到此這篇關于Java中關于String StringBuffer StringBuilder特性深度解析的文章就介紹到這了,更多相關Java String StringBuffer StringBuilder內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
- java String、StringBuilder和StringBuffer的區(qū)別詳解
- 詳解java中String、StringBuilder、StringBuffer的區(qū)別
- java中String、StringBuffer與StringBuilder的區(qū)別
- java中String StringBuffer和StringBuilder的區(qū)別詳解
- Java源碼深度分析String與StringBuffer及StringBuilder詳解
- Java中String和StringBuffer及StringBuilder?有什么區(qū)別
- 詳解Java中String,StringBuffer和StringBuilder的使用
- Java StringBuffer與StringBuilder有什么區(qū)別
- Java中String、StringBuffer和StringBuilder的區(qū)別
- 一文講解Java的String、StringBuffer和StringBuilder的使用與區(qū)別
相關文章
Java模擬撲克牌洗牌實現(xiàn)生成52張撲克的方法示例
這篇文章主要介紹了Java模擬撲克牌洗牌實現(xiàn)生成52張撲克的方法,涉及Java數(shù)組遍歷、重排及輸出等相關操作技巧,需要的朋友可以參考下2018-01-01dubbo服務引用之創(chuàng)建Invoker流程詳解
這篇文章主要為大家介紹了dubbo服務引用二之創(chuàng)建Invoker流程詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-08-08Mybatis查詢返回Map<String,Object>類型的實現(xiàn)
本文主要介紹了Mybatis查詢返回Map<String,Object>類型的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2023-07-07springmvc4+hibernate4分頁查詢功能實現(xiàn)
本篇文章主要介紹了springmvc4+hibernate4分頁查詢功能實現(xiàn),Springmvc+hibernate成為現(xiàn)在很多人用的框架整合,有興趣的可以了解一下。2017-01-01Java inputstream和outputstream使用詳解
這篇文章主要介紹了Java inputstream和outputstream使用詳解,本篇文章通過簡要的案例,講解了該項技術的了解與使用,以下就是詳細內(nèi)容,需要的朋友可以參考下2021-08-08