java新手入門——String類詳解
一、創(chuàng)建字符串
創(chuàng)建字符串的方式有很多種,當(dāng)是常見的一般就三種
1. 直接賦值(常用)
String str = "hello world !";
2. new String
String str = new String("hello world !");
3. 字符數(shù)組轉(zhuǎn)String
char[] array = {'a', 'b', 'c'}; String str = new String(array);
但以后一般都是用第一種創(chuàng)建方式
注意事項(xiàng):
"hello" 這樣的字符串字面值常量, 類型也是 String.String 也屬于引用類型. String str ="Hello"
4.String類中兩種對象實(shí)例化的區(qū)別
直接賦值:只會(huì)開辟一塊堆內(nèi)存空間,并且該字符串對象可以自動(dòng)保存在對象池中以供下次使用。構(gòu)造方法:會(huì)開辟兩塊堆內(nèi)存空間,不會(huì)自動(dòng)保存在對象池中,可以使用intern()方法手工入池。
二、字符串比較相等
1.直接比較字符串
我們知道兩個(gè)整形可以直接用 == 比較相等,那如果用 == 比較String類相等會(huì)發(fā)生什么呢?
代碼:
public static void main(String[] args) { String str1 = "hello"; String str2 = new String("hello"); System.out.println(str1 == str2); String str3 = "he"+"llo";//編譯的時(shí)候這個(gè)地方相當(dāng)于 String str3 = "hello"; System.out.println(str1 == str3); String str4 = "he"; String str5 = "llo"; String str6 = str4+str5; System.out.println(str1 == str6); String str7 = "he"+new String("llo"); System.out.println(str1 == str7); }
運(yùn)行結(jié)果:
我們知道String屬于引用類型,所以str存的是地址。那么比較的就是地址。
只要new了就會(huì)在堆上開辟內(nèi)存,所以不相等。直接說可能有點(diǎn)抽象,下面簡單通過內(nèi)存圖來判斷字符串是否相等。
2.字符串在內(nèi)存中的存儲(chǔ)
接上面的例子我們來看一下字符串在內(nèi)存中的存儲(chǔ)來判斷相等
注意:
1.只要new了就會(huì)在堆上開辟內(nèi)存,那么必定不會(huì)相等。
2.相同的字符串在字符串常量池里只會(huì)存一份。
3.字符串常量池
String類的設(shè)計(jì)使用了共享設(shè)計(jì)模式
在JVM底層實(shí)際上會(huì)自動(dòng)維護(hù)一個(gè)對象池(字符串常量池)
如果現(xiàn)在采用了直接賦值的模式進(jìn)行String類的對象實(shí)例化操作,那么該實(shí)例化對象(字符串內(nèi)容)將自動(dòng)保存到這個(gè)對象池之中.如果下次繼續(xù)使用直接賦值的模式聲明String類對象,此時(shí)對象池之中如若有指定內(nèi)容,將直接進(jìn)行引用如若沒有,則開辟新的字符串對象而后將其保存在對象池之中以供下次使用
4.字符串比較equals
Java 中要想比較字符串是否相等的話,就需要使用String提供的equals方法
String str1 = new String("Hello"); String str2 = new String("Hello"); System.out.println(str1.equals(str2)); // System.out.println(str2.equals(str1)); // 或者這樣寫也行 // 執(zhí)行結(jié)果 true
equals使用的注意事項(xiàng):
現(xiàn)在需要比較 str 和 “Hello” 兩個(gè)字符串是否相等, 我們該如何來寫呢?
String str = new String("Hello"); // 方式一 System.out.println(str.equals("Hello")); // 方式二 System.out.println("Hello".equals(str));
在上面的代碼中, 哪種方式更好呢?
更推薦使用 “方式二”. 一旦 str 是 null, 方式一的代碼會(huì)拋出異常, 而方式二不會(huì)
String str = null; // 方式一 System.out.println(str.equals("Hello")); // 執(zhí)行結(jié)果 拋出 java.lang.NullPointerException 異 常 // 方式二 System.out.println("Hello".equals(str)); // 執(zhí)行結(jié)果 false
注意事項(xiàng): “Hello” 這樣的字面值常量, 本質(zhì)上也是一個(gè) String 對象, 完全可以使用 equals 等 String 對象的方法
5.理解字符串的不可變
字符串是一種不可變對象. 它的內(nèi)容不可改變.
String 類的內(nèi)部實(shí)現(xiàn)也是基于 char[] 來實(shí)現(xiàn)的, 但是 String 類并沒有提供 set 方法之類的來修改內(nèi)部的字符數(shù)組.
代碼示例:
String str = "hello" ; str = str + " world" ; str += "!!!" ; System.out.println(str); // 執(zhí)行結(jié)果 hello world!!!
形如 += 這樣的操作, 表面上好像是修改了字符串, 其實(shí)不是. 內(nèi)存變化如下:
+= 之后 str 打印的結(jié)果卻是變了, 但是不是 String 對象本身發(fā)生改變, 而是 str 引用到了其他的對象.
回顧引用:
引用相當(dāng)于一個(gè)指針, 里面存的內(nèi)容是一個(gè)地址. 我們要區(qū)分清楚當(dāng)前修改到底是修改了地址對應(yīng)內(nèi)存的內(nèi)容發(fā)生改變了, 還是引用中存的地址改變了.
6.手動(dòng)入池 intern()
我們知道字符串常量是存在字符串常量池當(dāng)中的,而new的是在堆上開辟內(nèi)存。
而String的 intern()方法可以把String對象手動(dòng)入到字符串常量池中
// 該字符串常量并沒有保存在對象池之中 String str1 = "hello" ; String str2 = new String("hello") ; System.out.println(str1 == str2); // 執(zhí)行結(jié)果 false String str1 = "hello" ; String str2 = new String("hello").intern() ; System.out.println(str1 == str2); // 執(zhí)行結(jié)果 true
如果str2沒有
intern()方法的時(shí)候,它是指向堆上的new的String對象的,而使用了intern()方法后,就會(huì)直接指向字符串常量池的
”hello“,如果調(diào)用intern()方法的時(shí)候字符串常量池中沒有 "hello"這個(gè)字符串,則會(huì)把它放入池中。
三、字符字節(jié)與字符串
1.字符轉(zhuǎn)字符串
代碼示例 :
char[] array = {'h','e','l','l','o'}; String str1 = new String(array); String str2 = new String(array,1,2); System.out.println(str1); System.out.println(str2); //運(yùn)行結(jié)果 //hello //el
注意:第一個(gè)參數(shù)是偏移量,偏移量是從0開始的,第二個(gè)是參數(shù)是往后從偏移量開始的位置走幾步。且下標(biāo)不能越界!
2.字符串轉(zhuǎn)字符
指定獲取字符串里的某一個(gè)字符:
String str = "hello"; char ch = str.charAt(4); System.out.println(ch); //運(yùn)行結(jié)果 //o
字符串轉(zhuǎn)字符數(shù)組代碼示例:
String str = "hello"; char[] array = str.toCharArray(); for (char s : array) { System.out.print(s+" "); }
運(yùn)行結(jié)果
3.字節(jié)與字符串
用法和上面的類似
代碼示例:
byte[] bytes = {97,98,99,100}; String str = new String(bytes,1,3); System.out.println(str); String str2 = "abcd"; byte[] bytes1 = str2.getBytes(); System.out.println(Arrays.toString(bytes1));
運(yùn)行結(jié)果
4.編碼方式
運(yùn)行結(jié)果 :
常見的編碼方式有 utf-8 和 GBK ,不過編碼方式一般只對漢字有影響。
5.小結(jié)
那么何時(shí)使用 byte[], 何時(shí)使用 char[] 呢?
byte[] 是把 String 按照一個(gè)字節(jié)一個(gè)字節(jié)的方式處理, 這種適合在網(wǎng)絡(luò)傳輸, 數(shù)據(jù)存儲(chǔ)這樣的場景下使用. 更適合 針對二進(jìn)制數(shù)據(jù)來操作.char[] 是吧 String 按照一個(gè)字符一個(gè)字符的方式處理, 更適合針對文本數(shù)據(jù)來操作, 尤其是包含中文的時(shí)候
回憶概念: 文本數(shù)據(jù) vs 二進(jìn)制數(shù)據(jù)
一個(gè)簡單粗暴的區(qū)分方式就是用記事本打開能不能看懂里面的內(nèi)容.
如果看的懂, 就是文本數(shù)據(jù)(例如 .java 文件), 如果看不懂, 就是二進(jìn)制數(shù)據(jù)(例如 .class 文件).
四、字符串常見操作
1.字符串比較
上面使用過String類提供的equals()方法,該方法本身是可以進(jìn)行區(qū)分大小寫的相等判斷。除了這個(gè)方法之外,String類還提供有如下的比較操作:
代碼示例:
String str = "abcd"; System.out.println("abcd".equals(str)); System.out.println("Abcd".equalsIgnoreCase(str));//不區(qū)分大小寫 //運(yùn)行結(jié)果 //true //true
**compareTo()**方法前面博客有詳細(xì)介紹,這里就不多說了??梢钥纯础?gt;compareTo方法
在String類中compareTo()方法是一個(gè)非常重要的方法,該方法返回一個(gè)整型,該數(shù)據(jù)會(huì)根據(jù)大小關(guān)系返回三類內(nèi)
容:
相等:返回0.小于:返回內(nèi)容小于0.大于:返回內(nèi)容大于0。
2.字符串查找
從一個(gè)完整的字符串之中可以判斷指定內(nèi)容是否存在,對于查找方法有如下定義:
代碼示例 :
String str = "abcdefg"; 找子串 System.out.println(str.contains("efg")); 從頭開始找指定字符串,找到返回下標(biāo),找不到返回 -1 System.out.println(str.indexOf("d")); 指定位置開始找指定字符串 System.out.println(str.indexOf("d",2)); 從后向前找指定字符串 System.out.println(str.lastIndexOf("fg")); 判斷是否以指定字符串開頭 System.out.println(str.startsWith("abc")); 從指定位置判斷是否以該字符串開頭 System.out.println(str.startsWith("de", 3));
用法都是通過 String類點(diǎn)出方法名,注意就收放回值就好了。
3.字符串替換
使用一個(gè)指定的新的字符串替換掉已有的字符串?dāng)?shù)據(jù),可用的方法如下:
代碼示例:
String str = "helloworld" ; System.out.println(str.replaceAll("l", "!")); System.out.println(str.replaceFirst("l", "!"));
運(yùn)行結(jié)果
注意如果替換的是特殊字符,則需要使用轉(zhuǎn)義字符。
代碼示例:
String str1 = "192\\168\\1\\1" ; System.out.println(str1.replaceAll("\\\\", "+")); String str2 = "www.baidu.com"; System.out.println(str2.replaceAll("\\.", "%20"));
運(yùn)行結(jié)果
注意事項(xiàng): 由于字符串是不可變對象, 替換不修改當(dāng)前字符串, 而是產(chǎn)生一個(gè)新的字符串.
4.字符串拆分
可以將一個(gè)完整的字符串按照指定的分隔符劃分為若干個(gè)子字符串。
代碼示例:
String str1 = "192.168.1.1" ; String[] array = str1.split("\\."); for (String s : array) { System.out.println(s); }
運(yùn)行結(jié)果
注意:下面的的這段代碼是不能被拆分的
String str1 = "192\168\1\1" ; String[] array = str1.split("\\\\"); for (String s : array) { System.out.println(s); }
運(yùn)行結(jié)果:
因?yàn)?\ 后面跟兩到三個(gè)數(shù)字會(huì)被轉(zhuǎn)義成一個(gè)八進(jìn)制數(shù)字。
注意事項(xiàng):
字符"|","*","+“都得加上轉(zhuǎn)義字符,前面加上”".而如果是"",那么就得寫成"\".如果一個(gè)字符串中有多個(gè)分隔符,可以用"|"作為連字符.
多次拆分代碼示例:
String str = "name=zhangsan&age=18"; String[] result = str.split("&|=") ; for (String s : result) { System.out.println(s); }
運(yùn)行結(jié)果:
5.字符串截取
從一個(gè)完整的字符串之中截取出部分內(nèi)容。
代碼示例:
String str = "abcdef"; System.out.println(str.substring(3)); System.out.println(str.substring(2, 4));//左閉右開 運(yùn)行結(jié)果 def cd
注意事項(xiàng):
索引從0開始注意前閉后開區(qū)間的寫法, substring(0, 5) 表示包含 0 號(hào)下標(biāo)的字符, 不包含 5 號(hào)下標(biāo) 6.其他操作方法
這些都比較簡單,用的時(shí)候查就好了。
五、StringBuffer 和 StringBuilder
首先來回顧下String類的特點(diǎn):
任何的字符串常量都是String對象,而且String的常量一旦聲明不可改變,如果改變對象內(nèi)容,改變的是其引用的指向而已。
通常來講String的操作比較簡單,但是由于String的不可更改特性,為了方便字符串的修改,提供StringBuffer和StringBuilder類。
StringBuffer 和 StringBuilder 大部分功能是相同的,只有較小的區(qū)別。
1.append()方法
在String中使用"+"來進(jìn)行字符串連接,但是這個(gè)操作在StringBuffer類中需要更改為append()方法:
public synchronized StringBuffer append(各種數(shù)據(jù)類型 b)
代碼示例:
StringBuffer str1 = new StringBuffer("abcd"); StringBuilder str2 = new StringBuilder("abcd"); str1.append(123); str2.append("hij"); System.out.println(str1); System.out.println(str2);
運(yùn)行結(jié)果:
StringBuffer 和 StringBuilder 大部分功能是相同的,它們的append()方法的方法可以拼接各種數(shù)據(jù)類型。
注意:
String和StringBuffer最大的區(qū)別在于:String的內(nèi)容無法修改,而StringBuffer的內(nèi)容可以修改。頻繁修改字符串的情況考慮使用StingBuffer。
因?yàn)?String通過+拼接會(huì)產(chǎn)生臨時(shí)對象,而 StringBuffer 和 StringBuilder 只會(huì)在當(dāng)前對象上進(jìn)行拼接。
2.字符串反轉(zhuǎn) reverse( )
代碼示例:
StringBuffer str1 = new StringBuffer("abcdefg"); StringBuilder str2 = new StringBuilder("654321"); System.out.println(str1.reverse()); System.out.println(str2.reverse());
運(yùn)行結(jié)果:
3.刪除指定范圍的數(shù)據(jù) delete( )
代碼示例:
StringBuffer str1 = new StringBuffer("abcdefg"); StringBuilder str2 = new StringBuilder("654321"); System.out.println(str1.delete(2, 5)); System.out.println(str2.delete(4, 6));
運(yùn)行結(jié)果:
4.插入數(shù)據(jù) insert( )
代碼示例:
StringBuffer str1 = new StringBuffer("abcdefg"); StringBuilder str2 = new StringBuilder("654321"); str1.insert(0,"你好嗎").delete(0,1); System.out.println(str1); System.out.println(str2.delete(0, 3).insert(0, "你好世界"));
運(yùn)行結(jié)果:
5.StringBuffer 和 StringBuilder的區(qū)別
來看一下 StringBuffer 和 StringBuilder 的 append 方法
1.String的拼接會(huì)產(chǎn)生臨時(shí)對象,但是后兩者每次都只是返回當(dāng)前對象的引用
2.String的加號(hào)拼接,會(huì)被底層優(yōu)化為一個(gè)StringBuilder
3.StringBuilder和String,一般如果不涉及到多線程的情況下才會(huì)使用
4.StringBuffer(創(chuàng)建鎖、銷毀鎖、都是耗費(fèi)資源的)
總結(jié)
1.如果以后涉及到字符串的拼接,一定要使用 StringBuffer 和 StringBuilder 的 append()方法
2.注意String類中兩種對象實(shí)例化的區(qū)別
3.相同的字符串在字符串常量池中只會(huì)存一份
一、創(chuàng)建字符串
創(chuàng)建字符串的方式有很多種,當(dāng)是常見的一般就三種
1. 直接賦值(常用)
String str = "hello world !";
2. new String
String str = new String("hello world !");
3. 字符數(shù)組轉(zhuǎn)String
char[] array = {'a', 'b', 'c'}; String str = new String(array);
但以后一般都是用第一種創(chuàng)建方式
注意事項(xiàng):
"hello" 這樣的字符串字面值常量, 類型也是 String.String 也屬于引用類型. String str ="Hello"
4.String類中兩種對象實(shí)例化的區(qū)別
直接賦值:只會(huì)開辟一塊堆內(nèi)存空間,并且該字符串對象可以自動(dòng)保存在對象池中以供下次使用。構(gòu)造方法:會(huì)開辟兩塊堆內(nèi)存空間,不會(huì)自動(dòng)保存在對象池中,可以使用intern()方法手工入池。
二、字符串比較相等
1.直接比較字符串
我們知道兩個(gè)整形可以直接用 == 比較相等,那如果用 == 比較String類相等會(huì)發(fā)生什么呢?
代碼:
public static void main(String[] args) { String str1 = "hello"; String str2 = new String("hello"); System.out.println(str1 == str2); String str3 = "he"+"llo";//編譯的時(shí)候這個(gè)地方相當(dāng)于 String str3 = "hello"; System.out.println(str1 == str3); String str4 = "he"; String str5 = "llo"; String str6 = str4+str5; System.out.println(str1 == str6); String str7 = "he"+new String("llo"); System.out.println(str1 == str7); }
運(yùn)行結(jié)果:
我們知道String屬于引用類型,所以str存的是地址。那么比較的就是地址。
只要new了就會(huì)在堆上開辟內(nèi)存,所以不相等。直接說可能有點(diǎn)抽象,下面簡單通過內(nèi)存圖來判斷字符串是否相等。
2.字符串在內(nèi)存中的存儲(chǔ)
接上面的例子我們來看一下字符串在內(nèi)存中的存儲(chǔ)來判斷相等
注意:
1.只要new了就會(huì)在堆上開辟內(nèi)存,那么必定不會(huì)相等。
2.相同的字符串在字符串常量池里只會(huì)存一份。
3.字符串常量池
String類的設(shè)計(jì)使用了共享設(shè)計(jì)模式
在JVM底層實(shí)際上會(huì)自動(dòng)維護(hù)一個(gè)對象池(字符串常量池)
如果現(xiàn)在采用了直接賦值的模式進(jìn)行String類的對象實(shí)例化操作,那么該實(shí)例化對象(字符串內(nèi)容)將自動(dòng)保存到這個(gè)對象池之中.如果下次繼續(xù)使用直接賦值的模式聲明String類對象,此時(shí)對象池之中如若有指定內(nèi)容,將直接進(jìn)行引用如若沒有,則開辟新的字符串對象而后將其保存在對象池之中以供下次使用
4.字符串比較equals
Java 中要想比較字符串是否相等的話,就需要使用String提供的equals方法
String str1 = new String("Hello"); String str2 = new String("Hello"); System.out.println(str1.equals(str2)); // System.out.println(str2.equals(str1)); // 或者這樣寫也行 // 執(zhí)行結(jié)果 true
equals使用的注意事項(xiàng):
現(xiàn)在需要比較 str 和 “Hello” 兩個(gè)字符串是否相等, 我們該如何來寫呢?
String str = new String("Hello"); // 方式一 System.out.println(str.equals("Hello")); // 方式二 System.out.println("Hello".equals(str));
在上面的代碼中, 哪種方式更好呢?
更推薦使用 “方式二”. 一旦 str 是 null, 方式一的代碼會(huì)拋出異常, 而方式二不會(huì)
String str = null; // 方式一 System.out.println(str.equals("Hello")); // 執(zhí)行結(jié)果 拋出 java.lang.NullPointerException 異 常 // 方式二 System.out.println("Hello".equals(str)); // 執(zhí)行結(jié)果 false
注意事項(xiàng): “Hello” 這樣的字面值常量, 本質(zhì)上也是一個(gè) String 對象, 完全可以使用 equals 等 String 對象的方法
5.理解字符串的不可變
字符串是一種不可變對象. 它的內(nèi)容不可改變.
String 類的內(nèi)部實(shí)現(xiàn)也是基于 char[] 來實(shí)現(xiàn)的, 但是 String 類并沒有提供 set 方法之類的來修改內(nèi)部的字符數(shù)組.
代碼示例:
String str = "hello" ; str = str + " world" ; str += "!!!" ; System.out.println(str); // 執(zhí)行結(jié)果 hello world!!!
形如 += 這樣的操作, 表面上好像是修改了字符串, 其實(shí)不是. 內(nèi)存變化如下:
+= 之后 str 打印的結(jié)果卻是變了, 但是不是 String 對象本身發(fā)生改變, 而是 str 引用到了其他的對象.
回顧引用:
引用相當(dāng)于一個(gè)指針, 里面存的內(nèi)容是一個(gè)地址. 我們要區(qū)分清楚當(dāng)前修改到底是修改了地址對應(yīng)內(nèi)存的內(nèi)容發(fā)生改變了, 還是引用中存的地址改變了.
6.手動(dòng)入池 intern()
我們知道字符串常量是存在字符串常量池當(dāng)中的,而new的是在堆上開辟內(nèi)存。
而String的 intern()方法可以把String對象手動(dòng)入到字符串常量池中
// 該字符串常量并沒有保存在對象池之中 String str1 = "hello" ; String str2 = new String("hello") ; System.out.println(str1 == str2); // 執(zhí)行結(jié)果 false String str1 = "hello" ; String str2 = new String("hello").intern() ; System.out.println(str1 == str2); // 執(zhí)行結(jié)果 true
如果str2沒有
intern()方法的時(shí)候,它是指向堆上的new的String對象的,而使用了intern()方法后,就會(huì)直接指向字符串常量池的
”hello“,如果調(diào)用intern()方法的時(shí)候字符串常量池中沒有 "hello"這個(gè)字符串,則會(huì)把它放入池中。
三、字符字節(jié)與字符串
1.字符轉(zhuǎn)字符串
代碼示例 :
char[] array = {'h','e','l','l','o'}; String str1 = new String(array); String str2 = new String(array,1,2); System.out.println(str1); System.out.println(str2); //運(yùn)行結(jié)果 //hello //el
注意:第一個(gè)參數(shù)是偏移量,偏移量是從0開始的,第二個(gè)是參數(shù)是往后從偏移量開始的位置走幾步。且下標(biāo)不能越界!
2.字符串轉(zhuǎn)字符
指定獲取字符串里的某一個(gè)字符:
String str = "hello"; char ch = str.charAt(4); System.out.println(ch); //運(yùn)行結(jié)果 //o
字符串轉(zhuǎn)字符數(shù)組代碼示例:
String str = "hello"; char[] array = str.toCharArray(); for (char s : array) { System.out.print(s+" "); }
運(yùn)行結(jié)果
3.字節(jié)與字符串
用法和上面的類似
代碼示例:
byte[] bytes = {97,98,99,100}; String str = new String(bytes,1,3); System.out.println(str); String str2 = "abcd"; byte[] bytes1 = str2.getBytes(); System.out.println(Arrays.toString(bytes1));
運(yùn)行結(jié)果
4.編碼方式
運(yùn)行結(jié)果 :
常見的編碼方式有 utf-8 和 GBK ,不過編碼方式一般只對漢字有影響。
5.小結(jié)
那么何時(shí)使用 byte[], 何時(shí)使用 char[] 呢?
byte[] 是把 String 按照一個(gè)字節(jié)一個(gè)字節(jié)的方式處理, 這種適合在網(wǎng)絡(luò)傳輸, 數(shù)據(jù)存儲(chǔ)這樣的場景下使用. 更適合 針對二進(jìn)制數(shù)據(jù)來操作.char[] 是吧 String 按照一個(gè)字符一個(gè)字符的方式處理, 更適合針對文本數(shù)據(jù)來操作, 尤其是包含中文的時(shí)候
回憶概念: 文本數(shù)據(jù) vs 二進(jìn)制數(shù)據(jù)
一個(gè)簡單粗暴的區(qū)分方式就是用記事本打開能不能看懂里面的內(nèi)容.
如果看的懂, 就是文本數(shù)據(jù)(例如 .java 文件), 如果看不懂, 就是二進(jìn)制數(shù)據(jù)(例如 .class 文件).
四、字符串常見操作
1.字符串比較
上面使用過String類提供的equals()方法,該方法本身是可以進(jìn)行區(qū)分大小寫的相等判斷。除了這個(gè)方法之外,String類還提供有如下的比較操作:
代碼示例:
String str = "abcd"; System.out.println("abcd".equals(str)); System.out.println("Abcd".equalsIgnoreCase(str));//不區(qū)分大小寫 //運(yùn)行結(jié)果 //true //true
**compareTo()**方法前面博客有詳細(xì)介紹,這里就不多說了??梢钥纯础?gt;compareTo方法
在String類中compareTo()方法是一個(gè)非常重要的方法,該方法返回一個(gè)整型,該數(shù)據(jù)會(huì)根據(jù)大小關(guān)系返回三類內(nèi)
容:
相等:返回0.小于:返回內(nèi)容小于0.大于:返回內(nèi)容大于0。
2.字符串查找
從一個(gè)完整的字符串之中可以判斷指定內(nèi)容是否存在,對于查找方法有如下定義:
代碼示例 :
String str = "abcdefg"; 找子串 System.out.println(str.contains("efg")); 從頭開始找指定字符串,找到返回下標(biāo),找不到返回 -1 System.out.println(str.indexOf("d")); 指定位置開始找指定字符串 System.out.println(str.indexOf("d",2)); 從后向前找指定字符串 System.out.println(str.lastIndexOf("fg")); 判斷是否以指定字符串開頭 System.out.println(str.startsWith("abc")); 從指定位置判斷是否以該字符串開頭 System.out.println(str.startsWith("de", 3));
用法都是通過 String類點(diǎn)出方法名,注意就收放回值就好了。
3.字符串替換
使用一個(gè)指定的新的字符串替換掉已有的字符串?dāng)?shù)據(jù),可用的方法如下:
代碼示例:
String str = "helloworld" ; System.out.println(str.replaceAll("l", "!")); System.out.println(str.replaceFirst("l", "!"));
運(yùn)行結(jié)果
注意如果替換的是特殊字符,則需要使用轉(zhuǎn)義字符。
代碼示例:
String str1 = "192\\168\\1\\1" ; System.out.println(str1.replaceAll("\\\\", "+")); String str2 = "www.baidu.com"; System.out.println(str2.replaceAll("\\.", "%20"));
運(yùn)行結(jié)果
注意事項(xiàng): 由于字符串是不可變對象, 替換不修改當(dāng)前字符串, 而是產(chǎn)生一個(gè)新的字符串.
4.字符串拆分
可以將一個(gè)完整的字符串按照指定的分隔符劃分為若干個(gè)子字符串。
代碼示例:
String str1 = "192.168.1.1" ; String[] array = str1.split("\\."); for (String s : array) { System.out.println(s); }
運(yùn)行結(jié)果
注意:下面的的這段代碼是不能被拆分的
String str1 = "192\168\1\1" ; String[] array = str1.split("\\\\"); for (String s : array) { System.out.println(s); }
運(yùn)行結(jié)果:
因?yàn)?\ 后面跟兩到三個(gè)數(shù)字會(huì)被轉(zhuǎn)義成一個(gè)八進(jìn)制數(shù)字。
注意事項(xiàng):
字符"|","*","+“都得加上轉(zhuǎn)義字符,前面加上”".而如果是"",那么就得寫成"\".如果一個(gè)字符串中有多個(gè)分隔符,可以用"|"作為連字符.
多次拆分代碼示例:
String str = "name=zhangsan&age=18"; String[] result = str.split("&|=") ; for (String s : result) { System.out.println(s); }
運(yùn)行結(jié)果:
5.字符串截取
從一個(gè)完整的字符串之中截取出部分內(nèi)容。
代碼示例:
String str = "abcdef"; System.out.println(str.substring(3)); System.out.println(str.substring(2, 4));//左閉右開 運(yùn)行結(jié)果 def cd
注意事項(xiàng):
索引從0開始注意前閉后開區(qū)間的寫法, substring(0, 5) 表示包含 0 號(hào)下標(biāo)的字符, 不包含 5 號(hào)下標(biāo) 6.其他操作方法
這些都比較簡單,用的時(shí)候查就好了。
五、StringBuffer 和 StringBuilder
首先來回顧下String類的特點(diǎn):
任何的字符串常量都是String對象,而且String的常量一旦聲明不可改變,如果改變對象內(nèi)容,改變的是其引用的指向而已。
通常來講String的操作比較簡單,但是由于String的不可更改特性,為了方便字符串的修改,提供StringBuffer和StringBuilder類。
StringBuffer 和 StringBuilder 大部分功能是相同的,只有較小的區(qū)別。
1.append()方法
在String中使用"+"來進(jìn)行字符串連接,但是這個(gè)操作在StringBuffer類中需要更改為append()方法:
public synchronized StringBuffer append(各種數(shù)據(jù)類型 b)
代碼示例:
StringBuffer str1 = new StringBuffer("abcd"); StringBuilder str2 = new StringBuilder("abcd"); str1.append(123); str2.append("hij"); System.out.println(str1); System.out.println(str2);
運(yùn)行結(jié)果:
StringBuffer 和 StringBuilder 大部分功能是相同的,它們的append()方法的方法可以拼接各種數(shù)據(jù)類型。
注意:
String和StringBuffer最大的區(qū)別在于:String的內(nèi)容無法修改,而StringBuffer的內(nèi)容可以修改。頻繁修改字符串的情況考慮使用StingBuffer。
因?yàn)?String通過+拼接會(huì)產(chǎn)生臨時(shí)對象,而 StringBuffer 和 StringBuilder 只會(huì)在當(dāng)前對象上進(jìn)行拼接。
2.字符串反轉(zhuǎn) reverse( )
代碼示例:
StringBuffer str1 = new StringBuffer("abcdefg"); StringBuilder str2 = new StringBuilder("654321"); System.out.println(str1.reverse()); System.out.println(str2.reverse());
運(yùn)行結(jié)果:
3.刪除指定范圍的數(shù)據(jù) delete( )
代碼示例:
StringBuffer str1 = new StringBuffer("abcdefg"); StringBuilder str2 = new StringBuilder("654321"); System.out.println(str1.delete(2, 5)); System.out.println(str2.delete(4, 6));
運(yùn)行結(jié)果:
4.插入數(shù)據(jù) insert( )
代碼示例:
StringBuffer str1 = new StringBuffer("abcdefg"); StringBuilder str2 = new StringBuilder("654321"); str1.insert(0,"你好嗎").delete(0,1); System.out.println(str1); System.out.println(str2.delete(0, 3).insert(0, "你好世界"));
運(yùn)行結(jié)果:
5.StringBuffer 和 StringBuilder的區(qū)別
來看一下 StringBuffer 和 StringBuilder 的 append 方法
1.String的拼接會(huì)產(chǎn)生臨時(shí)對象,但是后兩者每次都只是返回當(dāng)前對象的引用
2.String的加號(hào)拼接,會(huì)被底層優(yōu)化為一個(gè)StringBuilder
3.StringBuilder和String,一般如果不涉及到多線程的情況下才會(huì)使用
4.StringBuffer(創(chuàng)建鎖、銷毀鎖、都是耗費(fèi)資源的)
六、總結(jié)
1.如果以后涉及到字符串的拼接,一定要使用 StringBuffer 和 StringBuilder 的 append()方法
2.注意String類中兩種對象實(shí)例化的區(qū)別
3.相同的字符串在字符串常量池中只會(huì)存一份
希望大家可以多多關(guān)注腳本之家的其他文章!
一、創(chuàng)建字符串
創(chuàng)建字符串的方式有很多種,當(dāng)是常見的一般就三種
1. 直接賦值(常用)
String str = "hello world !";
2. new String
String str = new String("hello world !");
3. 字符數(shù)組轉(zhuǎn)String
char[] array = {'a', 'b', 'c'}; String str = new String(array);
但以后一般都是用第一種創(chuàng)建方式
注意事項(xiàng):
"hello" 這樣的字符串字面值常量, 類型也是 String.String 也屬于引用類型. String str ="Hello"
4.String類中兩種對象實(shí)例化的區(qū)別
直接賦值:只會(huì)開辟一塊堆內(nèi)存空間,并且該字符串對象可以自動(dòng)保存在對象池中以供下次使用。構(gòu)造方法:會(huì)開辟兩塊堆內(nèi)存空間,不會(huì)自動(dòng)保存在對象池中,可以使用intern()方法手工入池。
二、字符串比較相等
1.直接比較字符串
我們知道兩個(gè)整形可以直接用 == 比較相等,那如果用 == 比較String類相等會(huì)發(fā)生什么呢?
代碼:
public static void main(String[] args) { String str1 = "hello"; String str2 = new String("hello"); System.out.println(str1 == str2); String str3 = "he"+"llo";//編譯的時(shí)候這個(gè)地方相當(dāng)于 String str3 = "hello"; System.out.println(str1 == str3); String str4 = "he"; String str5 = "llo"; String str6 = str4+str5; System.out.println(str1 == str6); String str7 = "he"+new String("llo"); System.out.println(str1 == str7); }
運(yùn)行結(jié)果:
我們知道String屬于引用類型,所以str存的是地址。那么比較的就是地址。
只要new了就會(huì)在堆上開辟內(nèi)存,所以不相等。直接說可能有點(diǎn)抽象,下面簡單通過內(nèi)存圖來判斷字符串是否相等。
2.字符串在內(nèi)存中的存儲(chǔ)
接上面的例子我們來看一下字符串在內(nèi)存中的存儲(chǔ)來判斷相等
注意:
1.只要new了就會(huì)在堆上開辟內(nèi)存,那么必定不會(huì)相等。
2.相同的字符串在字符串常量池里只會(huì)存一份。
3.字符串常量池
String類的設(shè)計(jì)使用了共享設(shè)計(jì)模式
在JVM底層實(shí)際上會(huì)自動(dòng)維護(hù)一個(gè)對象池(字符串常量池)
如果現(xiàn)在采用了直接賦值的模式進(jìn)行String類的對象實(shí)例化操作,那么該實(shí)例化對象(字符串內(nèi)容)將自動(dòng)保存到這個(gè)對象池之中.如果下次繼續(xù)使用直接賦值的模式聲明String類對象,此時(shí)對象池之中如若有指定內(nèi)容,將直接進(jìn)行引用如若沒有,則開辟新的字符串對象而后將其保存在對象池之中以供下次使用
4.字符串比較equals
Java 中要想比較字符串是否相等的話,就需要使用String提供的equals方法
String str1 = new String("Hello"); String str2 = new String("Hello"); System.out.println(str1.equals(str2)); // System.out.println(str2.equals(str1)); // 或者這樣寫也行 // 執(zhí)行結(jié)果 true
equals使用的注意事項(xiàng):
現(xiàn)在需要比較 str 和 “Hello” 兩個(gè)字符串是否相等, 我們該如何來寫呢?
String str = new String("Hello"); // 方式一 System.out.println(str.equals("Hello")); // 方式二 System.out.println("Hello".equals(str));
在上面的代碼中, 哪種方式更好呢?
更推薦使用 “方式二”. 一旦 str 是 null, 方式一的代碼會(huì)拋出異常, 而方式二不會(huì)
String str = null; // 方式一 System.out.println(str.equals("Hello")); // 執(zhí)行結(jié)果 拋出 java.lang.NullPointerException 異 常 // 方式二 System.out.println("Hello".equals(str)); // 執(zhí)行結(jié)果 false
注意事項(xiàng): “Hello” 這樣的字面值常量, 本質(zhì)上也是一個(gè) String 對象, 完全可以使用 equals 等 String 對象的方法
5.理解字符串的不可變
字符串是一種不可變對象. 它的內(nèi)容不可改變.
String 類的內(nèi)部實(shí)現(xiàn)也是基于 char[] 來實(shí)現(xiàn)的, 但是 String 類并沒有提供 set 方法之類的來修改內(nèi)部的字符數(shù)組.
代碼示例:
String str = "hello" ; str = str + " world" ; str += "!!!" ; System.out.println(str); // 執(zhí)行結(jié)果 hello world!!!
形如 += 這樣的操作, 表面上好像是修改了字符串, 其實(shí)不是. 內(nèi)存變化如下:
+= 之后 str 打印的結(jié)果卻是變了, 但是不是 String 對象本身發(fā)生改變, 而是 str 引用到了其他的對象.
回顧引用:
引用相當(dāng)于一個(gè)指針, 里面存的內(nèi)容是一個(gè)地址. 我們要區(qū)分清楚當(dāng)前修改到底是修改了地址對應(yīng)內(nèi)存的內(nèi)容發(fā)生改變了, 還是引用中存的地址改變了.
6.手動(dòng)入池 intern()
我們知道字符串常量是存在字符串常量池當(dāng)中的,而new的是在堆上開辟內(nèi)存。
而String的 intern()方法可以把String對象手動(dòng)入到字符串常量池中
// 該字符串常量并沒有保存在對象池之中 String str1 = "hello" ; String str2 = new String("hello") ; System.out.println(str1 == str2); // 執(zhí)行結(jié)果 false String str1 = "hello" ; String str2 = new String("hello").intern() ; System.out.println(str1 == str2); // 執(zhí)行結(jié)果 true
如果str2沒有
intern()方法的時(shí)候,它是指向堆上的new的String對象的,而使用了intern()方法后,就會(huì)直接指向字符串常量池的
”hello“,如果調(diào)用intern()方法的時(shí)候字符串常量池中沒有 "hello"這個(gè)字符串,則會(huì)把它放入池中。
三、字符字節(jié)與字符串
1.字符轉(zhuǎn)字符串
代碼示例 :
char[] array = {'h','e','l','l','o'}; String str1 = new String(array); String str2 = new String(array,1,2); System.out.println(str1); System.out.println(str2); //運(yùn)行結(jié)果 //hello //el
注意:第一個(gè)參數(shù)是偏移量,偏移量是從0開始的,第二個(gè)是參數(shù)是往后從偏移量開始的位置走幾步。且下標(biāo)不能越界!
2.字符串轉(zhuǎn)字符
指定獲取字符串里的某一個(gè)字符:
String str = "hello"; char ch = str.charAt(4); System.out.println(ch); //運(yùn)行結(jié)果 //o
字符串轉(zhuǎn)字符數(shù)組代碼示例:
String str = "hello"; char[] array = str.toCharArray(); for (char s : array) { System.out.print(s+" "); }
運(yùn)行結(jié)果
3.字節(jié)與字符串
用法和上面的類似
代碼示例:
byte[] bytes = {97,98,99,100}; String str = new String(bytes,1,3); System.out.println(str); String str2 = "abcd"; byte[] bytes1 = str2.getBytes(); System.out.println(Arrays.toString(bytes1));
運(yùn)行結(jié)果
4.編碼方式
運(yùn)行結(jié)果 :
常見的編碼方式有 utf-8 和 GBK ,不過編碼方式一般只對漢字有影響。
5.小結(jié)
那么何時(shí)使用 byte[], 何時(shí)使用 char[] 呢?
byte[] 是把 String 按照一個(gè)字節(jié)一個(gè)字節(jié)的方式處理, 這種適合在網(wǎng)絡(luò)傳輸, 數(shù)據(jù)存儲(chǔ)這樣的場景下使用. 更適合 針對二進(jìn)制數(shù)據(jù)來操作.char[] 是吧 String 按照一個(gè)字符一個(gè)字符的方式處理, 更適合針對文本數(shù)據(jù)來操作, 尤其是包含中文的時(shí)候
回憶概念: 文本數(shù)據(jù) vs 二進(jìn)制數(shù)據(jù)
一個(gè)簡單粗暴的區(qū)分方式就是用記事本打開能不能看懂里面的內(nèi)容.
如果看的懂, 就是文本數(shù)據(jù)(例如 .java 文件), 如果看不懂, 就是二進(jìn)制數(shù)據(jù)(例如 .class 文件).
四、字符串常見操作
1.字符串比較
上面使用過String類提供的equals()方法,該方法本身是可以進(jìn)行區(qū)分大小寫的相等判斷。除了這個(gè)方法之外,String類還提供有如下的比較操作:
代碼示例:
String str = "abcd"; System.out.println("abcd".equals(str)); System.out.println("Abcd".equalsIgnoreCase(str));//不區(qū)分大小寫 //運(yùn)行結(jié)果 //true //true
**compareTo()**方法前面博客有詳細(xì)介紹,這里就不多說了。可以看看—>compareTo方法
在String類中compareTo()方法是一個(gè)非常重要的方法,該方法返回一個(gè)整型,該數(shù)據(jù)會(huì)根據(jù)大小關(guān)系返回三類內(nèi)
容:
相等:返回0.小于:返回內(nèi)容小于0.大于:返回內(nèi)容大于0。
2.字符串查找
從一個(gè)完整的字符串之中可以判斷指定內(nèi)容是否存在,對于查找方法有如下定義:
代碼示例 :
String str = "abcdefg"; 找子串 System.out.println(str.contains("efg")); 從頭開始找指定字符串,找到返回下標(biāo),找不到返回 -1 System.out.println(str.indexOf("d")); 指定位置開始找指定字符串 System.out.println(str.indexOf("d",2)); 從后向前找指定字符串 System.out.println(str.lastIndexOf("fg")); 判斷是否以指定字符串開頭 System.out.println(str.startsWith("abc")); 從指定位置判斷是否以該字符串開頭 System.out.println(str.startsWith("de", 3));
用法都是通過 String類點(diǎn)出方法名,注意就收放回值就好了。
3.字符串替換
使用一個(gè)指定的新的字符串替換掉已有的字符串?dāng)?shù)據(jù),可用的方法如下:
代碼示例:
String str = "helloworld" ; System.out.println(str.replaceAll("l", "!")); System.out.println(str.replaceFirst("l", "!"));
運(yùn)行結(jié)果
注意如果替換的是特殊字符,則需要使用轉(zhuǎn)義字符。
代碼示例:
String str1 = "192\\168\\1\\1" ; System.out.println(str1.replaceAll("\\\\", "+")); String str2 = "www.baidu.com"; System.out.println(str2.replaceAll("\\.", "%20"));
運(yùn)行結(jié)果
注意事項(xiàng): 由于字符串是不可變對象, 替換不修改當(dāng)前字符串, 而是產(chǎn)生一個(gè)新的字符串.
4.字符串拆分
可以將一個(gè)完整的字符串按照指定的分隔符劃分為若干個(gè)子字符串。
代碼示例:
String str1 = "192.168.1.1" ; String[] array = str1.split("\\."); for (String s : array) { System.out.println(s); }
運(yùn)行結(jié)果
注意:下面的的這段代碼是不能被拆分的
String str1 = "192\168\1\1" ; String[] array = str1.split("\\\\"); for (String s : array) { System.out.println(s); }
運(yùn)行結(jié)果:
因?yàn)?\ 后面跟兩到三個(gè)數(shù)字會(huì)被轉(zhuǎn)義成一個(gè)八進(jìn)制數(shù)字。
注意事項(xiàng):
字符"|","*","+“都得加上轉(zhuǎn)義字符,前面加上”".而如果是"",那么就得寫成"\".如果一個(gè)字符串中有多個(gè)分隔符,可以用"|"作為連字符.
多次拆分代碼示例:
String str = "name=zhangsan&age=18"; String[] result = str.split("&|=") ; for (String s : result) { System.out.println(s); }
運(yùn)行結(jié)果:
5.字符串截取
從一個(gè)完整的字符串之中截取出部分內(nèi)容。
代碼示例:
String str = "abcdef"; System.out.println(str.substring(3)); System.out.println(str.substring(2, 4));//左閉右開 運(yùn)行結(jié)果 def cd
注意事項(xiàng):
索引從0開始注意前閉后開區(qū)間的寫法, substring(0, 5) 表示包含 0 號(hào)下標(biāo)的字符, 不包含 5 號(hào)下標(biāo) 6.其他操作方法
這些都比較簡單,用的時(shí)候查就好了。
五、StringBuffer 和 StringBuilder
首先來回顧下String類的特點(diǎn):
任何的字符串常量都是String對象,而且String的常量一旦聲明不可改變,如果改變對象內(nèi)容,改變的是其引用的指向而已。
通常來講String的操作比較簡單,但是由于String的不可更改特性,為了方便字符串的修改,提供StringBuffer和StringBuilder類。
StringBuffer 和 StringBuilder 大部分功能是相同的,只有較小的區(qū)別。
1.append()方法
在String中使用"+"來進(jìn)行字符串連接,但是這個(gè)操作在StringBuffer類中需要更改為append()方法:
public synchronized StringBuffer append(各種數(shù)據(jù)類型 b)
代碼示例:
StringBuffer str1 = new StringBuffer("abcd"); StringBuilder str2 = new StringBuilder("abcd"); str1.append(123); str2.append("hij"); System.out.println(str1); System.out.println(str2);
運(yùn)行結(jié)果:
StringBuffer 和 StringBuilder 大部分功能是相同的,它們的append()方法的方法可以拼接各種數(shù)據(jù)類型。
注意:
String和StringBuffer最大的區(qū)別在于:String的內(nèi)容無法修改,而StringBuffer的內(nèi)容可以修改。頻繁修改字符串的情況考慮使用StingBuffer。
因?yàn)?String通過+拼接會(huì)產(chǎn)生臨時(shí)對象,而 StringBuffer 和 StringBuilder 只會(huì)在當(dāng)前對象上進(jìn)行拼接。
2.字符串反轉(zhuǎn) reverse( )
代碼示例:
StringBuffer str1 = new StringBuffer("abcdefg"); StringBuilder str2 = new StringBuilder("654321"); System.out.println(str1.reverse()); System.out.println(str2.reverse());
運(yùn)行結(jié)果:
3.刪除指定范圍的數(shù)據(jù) delete( )
代碼示例:
StringBuffer str1 = new StringBuffer("abcdefg"); StringBuilder str2 = new StringBuilder("654321"); System.out.println(str1.delete(2, 5)); System.out.println(str2.delete(4, 6));
運(yùn)行結(jié)果:
4.插入數(shù)據(jù) insert( )
代碼示例:
StringBuffer str1 = new StringBuffer("abcdefg"); StringBuilder str2 = new StringBuilder("654321"); str1.insert(0,"你好嗎").delete(0,1); System.out.println(str1); System.out.println(str2.delete(0, 3).insert(0, "你好世界"));
運(yùn)行結(jié)果:
5.StringBuffer 和 StringBuilder的區(qū)別
來看一下 StringBuffer 和 StringBuilder 的 append 方法
1.String的拼接會(huì)產(chǎn)生臨時(shí)對象,但是后兩者每次都只是返回當(dāng)前對象的引用
2.String的加號(hào)拼接,會(huì)被底層優(yōu)化為一個(gè)StringBuilder
3.StringBuilder和String,一般如果不涉及到多線程的情況下才會(huì)使用
4.StringBuffer(創(chuàng)建鎖、銷毀鎖、都是耗費(fèi)資源的)
總結(jié)
1.如果以后涉及到字符串的拼接,一定要使用 StringBuffer 和 StringBuilder 的 append()方法
2.注意String類中兩種對象實(shí)例化的區(qū)別
3.相同的字符串在字符串常量池中只會(huì)存一份
一、創(chuàng)建字符串
創(chuàng)建字符串的方式有很多種,當(dāng)是常見的一般就三種
1. 直接賦值(常用)
String str = "hello world !";
2. new String
String str = new String("hello world !");
3. 字符數(shù)組轉(zhuǎn)String
char[] array = {'a', 'b', 'c'}; String str = new String(array);
但以后一般都是用第一種創(chuàng)建方式
注意事項(xiàng):
"hello" 這樣的字符串字面值常量, 類型也是 String.String 也屬于引用類型. String str ="Hello"
4.String類中兩種對象實(shí)例化的區(qū)別
直接賦值:只會(huì)開辟一塊堆內(nèi)存空間,并且該字符串對象可以自動(dòng)保存在對象池中以供下次使用。構(gòu)造方法:會(huì)開辟兩塊堆內(nèi)存空間,不會(huì)自動(dòng)保存在對象池中,可以使用intern()方法手工入池。
二、字符串比較相等
1.直接比較字符串
我們知道兩個(gè)整形可以直接用 == 比較相等,那如果用 == 比較String類相等會(huì)發(fā)生什么呢?
代碼:
public static void main(String[] args) { String str1 = "hello"; String str2 = new String("hello"); System.out.println(str1 == str2); String str3 = "he"+"llo";//編譯的時(shí)候這個(gè)地方相當(dāng)于 String str3 = "hello"; System.out.println(str1 == str3); String str4 = "he"; String str5 = "llo"; String str6 = str4+str5; System.out.println(str1 == str6); String str7 = "he"+new String("llo"); System.out.println(str1 == str7); }
運(yùn)行結(jié)果:
我們知道String屬于引用類型,所以str存的是地址。那么比較的就是地址。
只要new了就會(huì)在堆上開辟內(nèi)存,所以不相等。直接說可能有點(diǎn)抽象,下面簡單通過內(nèi)存圖來判斷字符串是否相等。
2.字符串在內(nèi)存中的存儲(chǔ)
接上面的例子我們來看一下字符串在內(nèi)存中的存儲(chǔ)來判斷相等
注意:
1.只要new了就會(huì)在堆上開辟內(nèi)存,那么必定不會(huì)相等。
2.相同的字符串在字符串常量池里只會(huì)存一份。
3.字符串常量池
String類的設(shè)計(jì)使用了共享設(shè)計(jì)模式
在JVM底層實(shí)際上會(huì)自動(dòng)維護(hù)一個(gè)對象池(字符串常量池)
如果現(xiàn)在采用了直接賦值的模式進(jìn)行String類的對象實(shí)例化操作,那么該實(shí)例化對象(字符串內(nèi)容)將自動(dòng)保存到這個(gè)對象池之中.如果下次繼續(xù)使用直接賦值的模式聲明String類對象,此時(shí)對象池之中如若有指定內(nèi)容,將直接進(jìn)行引用如若沒有,則開辟新的字符串對象而后將其保存在對象池之中以供下次使用
4.字符串比較equals
Java 中要想比較字符串是否相等的話,就需要使用String提供的equals方法
String str1 = new String("Hello"); String str2 = new String("Hello"); System.out.println(str1.equals(str2)); // System.out.println(str2.equals(str1)); // 或者這樣寫也行 // 執(zhí)行結(jié)果 true
equals使用的注意事項(xiàng):
現(xiàn)在需要比較 str 和 “Hello” 兩個(gè)字符串是否相等, 我們該如何來寫呢?
String str = new String("Hello"); // 方式一 System.out.println(str.equals("Hello")); // 方式二 System.out.println("Hello".equals(str));
在上面的代碼中, 哪種方式更好呢?
更推薦使用 “方式二”. 一旦 str 是 null, 方式一的代碼會(huì)拋出異常, 而方式二不會(huì)
String str = null; // 方式一 System.out.println(str.equals("Hello")); // 執(zhí)行結(jié)果 拋出 java.lang.NullPointerException 異 常 // 方式二 System.out.println("Hello".equals(str)); // 執(zhí)行結(jié)果 false
注意事項(xiàng): “Hello” 這樣的字面值常量, 本質(zhì)上也是一個(gè) String 對象, 完全可以使用 equals 等 String 對象的方法
5.理解字符串的不可變
字符串是一種不可變對象. 它的內(nèi)容不可改變.
String 類的內(nèi)部實(shí)現(xiàn)也是基于 char[] 來實(shí)現(xiàn)的, 但是 String 類并沒有提供 set 方法之類的來修改內(nèi)部的字符數(shù)組.
代碼示例:
String str = "hello" ; str = str + " world" ; str += "!!!" ; System.out.println(str); // 執(zhí)行結(jié)果 hello world!!!
形如 += 這樣的操作, 表面上好像是修改了字符串, 其實(shí)不是. 內(nèi)存變化如下:
+= 之后 str 打印的結(jié)果卻是變了, 但是不是 String 對象本身發(fā)生改變, 而是 str 引用到了其他的對象.
回顧引用:
引用相當(dāng)于一個(gè)指針, 里面存的內(nèi)容是一個(gè)地址. 我們要區(qū)分清楚當(dāng)前修改到底是修改了地址對應(yīng)內(nèi)存的內(nèi)容發(fā)生改變了, 還是引用中存的地址改變了.
6.手動(dòng)入池 intern()
我們知道字符串常量是存在字符串常量池當(dāng)中的,而new的是在堆上開辟內(nèi)存。
而String的 intern()方法可以把String對象手動(dòng)入到字符串常量池中
// 該字符串常量并沒有保存在對象池之中 String str1 = "hello" ; String str2 = new String("hello") ; System.out.println(str1 == str2); // 執(zhí)行結(jié)果 false String str1 = "hello" ; String str2 = new String("hello").intern() ; System.out.println(str1 == str2); // 執(zhí)行結(jié)果 true
如果str2沒有
intern()方法的時(shí)候,它是指向堆上的new的String對象的,而使用了intern()方法后,就會(huì)直接指向字符串常量池的
”hello“,如果調(diào)用intern()方法的時(shí)候字符串常量池中沒有 "hello"這個(gè)字符串,則會(huì)把它放入池中。
三、字符字節(jié)與字符串
1.字符轉(zhuǎn)字符串
代碼示例 :
char[] array = {'h','e','l','l','o'}; String str1 = new String(array); String str2 = new String(array,1,2); System.out.println(str1); System.out.println(str2); //運(yùn)行結(jié)果 //hello //el
注意:第一個(gè)參數(shù)是偏移量,偏移量是從0開始的,第二個(gè)是參數(shù)是往后從偏移量開始的位置走幾步。且下標(biāo)不能越界!
2.字符串轉(zhuǎn)字符
指定獲取字符串里的某一個(gè)字符:
String str = "hello"; char ch = str.charAt(4); System.out.println(ch); //運(yùn)行結(jié)果 //o
字符串轉(zhuǎn)字符數(shù)組代碼示例:
String str = "hello"; char[] array = str.toCharArray(); for (char s : array) { System.out.print(s+" "); }
運(yùn)行結(jié)果
3.字節(jié)與字符串
用法和上面的類似
代碼示例:
byte[] bytes = {97,98,99,100}; String str = new String(bytes,1,3); System.out.println(str); String str2 = "abcd"; byte[] bytes1 = str2.getBytes(); System.out.println(Arrays.toString(bytes1));
運(yùn)行結(jié)果
4.編碼方式
運(yùn)行結(jié)果 :
常見的編碼方式有 utf-8 和 GBK ,不過編碼方式一般只對漢字有影響。
5.小結(jié)
那么何時(shí)使用 byte[], 何時(shí)使用 char[] 呢?
byte[] 是把 String 按照一個(gè)字節(jié)一個(gè)字節(jié)的方式處理, 這種適合在網(wǎng)絡(luò)傳輸, 數(shù)據(jù)存儲(chǔ)這樣的場景下使用. 更適合 針對二進(jìn)制數(shù)據(jù)來操作.char[] 是吧 String 按照一個(gè)字符一個(gè)字符的方式處理, 更適合針對文本數(shù)據(jù)來操作, 尤其是包含中文的時(shí)候
回憶概念: 文本數(shù)據(jù) vs 二進(jìn)制數(shù)據(jù)
一個(gè)簡單粗暴的區(qū)分方式就是用記事本打開能不能看懂里面的內(nèi)容.
如果看的懂, 就是文本數(shù)據(jù)(例如 .java 文件), 如果看不懂, 就是二進(jìn)制數(shù)據(jù)(例如 .class 文件).
四、字符串常見操作
1.字符串比較
上面使用過String類提供的equals()方法,該方法本身是可以進(jìn)行區(qū)分大小寫的相等判斷。除了這個(gè)方法之外,String類還提供有如下的比較操作:
代碼示例:
String str = "abcd"; System.out.println("abcd".equals(str)); System.out.println("Abcd".equalsIgnoreCase(str));//不區(qū)分大小寫 //運(yùn)行結(jié)果 //true //true
**compareTo()**方法前面博客有詳細(xì)介紹,這里就不多說了。可以看看—>compareTo方法
在String類中compareTo()方法是一個(gè)非常重要的方法,該方法返回一個(gè)整型,該數(shù)據(jù)會(huì)根據(jù)大小關(guān)系返回三類內(nèi)
容:
相等:返回0.小于:返回內(nèi)容小于0.大于:返回內(nèi)容大于0。
2.字符串查找
從一個(gè)完整的字符串之中可以判斷指定內(nèi)容是否存在,對于查找方法有如下定義:
代碼示例 :
String str = "abcdefg"; 找子串 System.out.println(str.contains("efg")); 從頭開始找指定字符串,找到返回下標(biāo),找不到返回 -1 System.out.println(str.indexOf("d")); 指定位置開始找指定字符串 System.out.println(str.indexOf("d",2)); 從后向前找指定字符串 System.out.println(str.lastIndexOf("fg")); 判斷是否以指定字符串開頭 System.out.println(str.startsWith("abc")); 從指定位置判斷是否以該字符串開頭 System.out.println(str.startsWith("de", 3));
用法都是通過 String類點(diǎn)出方法名,注意就收放回值就好了。
3.字符串替換
使用一個(gè)指定的新的字符串替換掉已有的字符串?dāng)?shù)據(jù),可用的方法如下:
代碼示例:
String str = "helloworld" ; System.out.println(str.replaceAll("l", "!")); System.out.println(str.replaceFirst("l", "!"));
運(yùn)行結(jié)果
注意如果替換的是特殊字符,則需要使用轉(zhuǎn)義字符。
代碼示例:
String str1 = "192\\168\\1\\1" ; System.out.println(str1.replaceAll("\\\\", "+")); String str2 = "www.baidu.com"; System.out.println(str2.replaceAll("\\.", "%20"));
運(yùn)行結(jié)果
注意事項(xiàng): 由于字符串是不可變對象, 替換不修改當(dāng)前字符串, 而是產(chǎn)生一個(gè)新的字符串.
4.字符串拆分
可以將一個(gè)完整的字符串按照指定的分隔符劃分為若干個(gè)子字符串。
代碼示例:
String str1 = "192.168.1.1" ; String[] array = str1.split("\\."); for (String s : array) { System.out.println(s); }
運(yùn)行結(jié)果
注意:下面的的這段代碼是不能被拆分的
String str1 = "192\168\1\1" ; String[] array = str1.split("\\\\"); for (String s : array) { System.out.println(s); }
運(yùn)行結(jié)果:
因?yàn)?\ 后面跟兩到三個(gè)數(shù)字會(huì)被轉(zhuǎn)義成一個(gè)八進(jìn)制數(shù)字。
注意事項(xiàng):
字符"|","*","+“都得加上轉(zhuǎn)義字符,前面加上”".而如果是"",那么就得寫成"\".如果一個(gè)字符串中有多個(gè)分隔符,可以用"|"作為連字符.
多次拆分代碼示例:
String str = "name=zhangsan&age=18"; String[] result = str.split("&|=") ; for (String s : result) { System.out.println(s); }
運(yùn)行結(jié)果:
5.字符串截取
從一個(gè)完整的字符串之中截取出部分內(nèi)容。
代碼示例:
String str = "abcdef"; System.out.println(str.substring(3)); System.out.println(str.substring(2, 4));//左閉右開 運(yùn)行結(jié)果 def cd
注意事項(xiàng):
索引從0開始注意前閉后開區(qū)間的寫法, substring(0, 5) 表示包含 0 號(hào)下標(biāo)的字符, 不包含 5 號(hào)下標(biāo) 6.其他操作方法
這些都比較簡單,用的時(shí)候查就好了。
五、StringBuffer 和 StringBuilder
首先來回顧下String類的特點(diǎn):
任何的字符串常量都是String對象,而且String的常量一旦聲明不可改變,如果改變對象內(nèi)容,改變的是其引用的指向而已。
通常來講String的操作比較簡單,但是由于String的不可更改特性,為了方便字符串的修改,提供StringBuffer和StringBuilder類。
StringBuffer 和 StringBuilder 大部分功能是相同的,只有較小的區(qū)別。
1.append()方法
在String中使用"+"來進(jìn)行字符串連接,但是這個(gè)操作在StringBuffer類中需要更改為append()方法:
public synchronized StringBuffer append(各種數(shù)據(jù)類型 b)
代碼示例:
StringBuffer str1 = new StringBuffer("abcd"); StringBuilder str2 = new StringBuilder("abcd"); str1.append(123); str2.append("hij"); System.out.println(str1); System.out.println(str2);
運(yùn)行結(jié)果:
StringBuffer 和 StringBuilder 大部分功能是相同的,它們的append()方法的方法可以拼接各種數(shù)據(jù)類型。
注意:
String和StringBuffer最大的區(qū)別在于:String的內(nèi)容無法修改,而StringBuffer的內(nèi)容可以修改。頻繁修改字符串的情況考慮使用StingBuffer。
因?yàn)?String通過+拼接會(huì)產(chǎn)生臨時(shí)對象,而 StringBuffer 和 StringBuilder 只會(huì)在當(dāng)前對象上進(jìn)行拼接。
2.字符串反轉(zhuǎn) reverse( )
代碼示例:
StringBuffer str1 = new StringBuffer("abcdefg"); StringBuilder str2 = new StringBuilder("654321"); System.out.println(str1.reverse()); System.out.println(str2.reverse());
運(yùn)行結(jié)果:
3.刪除指定范圍的數(shù)據(jù) delete( )
代碼示例:
StringBuffer str1 = new StringBuffer("abcdefg"); StringBuilder str2 = new StringBuilder("654321"); System.out.println(str1.delete(2, 5)); System.out.println(str2.delete(4, 6));
運(yùn)行結(jié)果:
4.插入數(shù)據(jù) insert( )
代碼示例:
StringBuffer str1 = new StringBuffer("abcdefg"); StringBuilder str2 = new StringBuilder("654321"); str1.insert(0,"你好嗎").delete(0,1); System.out.println(str1); System.out.println(str2.delete(0, 3).insert(0, "你好世界"));
運(yùn)行結(jié)果:
5.StringBuffer 和 StringBuilder的區(qū)別
來看一下 StringBuffer 和 StringBuilder 的 append 方法
1.String的拼接會(huì)產(chǎn)生臨時(shí)對象,但是后兩者每次都只是返回當(dāng)前對象的引用
2.String的加號(hào)拼接,會(huì)被底層優(yōu)化為一個(gè)StringBuilder
3.StringBuilder和String,一般如果不涉及到多線程的情況下才會(huì)使用
4.StringBuffer(創(chuàng)建鎖、銷毀鎖、都是耗費(fèi)資源的)
六、總結(jié)
1.如果以后涉及到字符串的拼接,一定要使用 StringBuffer 和 StringBuilder 的 append()方法
2.注意String類中兩種對象實(shí)例化的區(qū)別
3.相同的字符串在字符串常量池中只會(huì)存一份
希望大家可以多多關(guān)注腳本之家的其他文章!
相關(guān)文章
java基于swing實(shí)現(xiàn)的五子棋游戲代碼
這篇文章主要介紹了java基于swing實(shí)現(xiàn)的五子棋游戲代碼,主要涉及圖形界面與數(shù)組的用法,有不錯(cuò)的參考借鑒價(jià)值,需要的朋友可以參考下2014-11-11基于Java swing組件實(shí)現(xiàn)簡易計(jì)算器
這篇文章主要介紹了基于Java swing組件實(shí)現(xiàn)簡易計(jì)算器,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-04-04git stash 和unstash的使用操作,git unstash failed
這篇文章主要介紹了git stash 和unstash的使用操作,git unstash failed,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-02-02Spring Boot如何使用Spring Security進(jìn)行安全控制
要實(shí)現(xiàn)訪問控制的方法多種多樣,可以通過Aop、攔截器實(shí)現(xiàn),也可以通過框架實(shí)現(xiàn),本文將具體介紹在Spring Boot中如何使用Spring Security進(jìn)行安全控制。2017-04-04elasticsearch bucket 之rare terms聚合使用詳解
這篇文章主要為大家介紹了elasticsearch bucket 之rare terms聚合使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11Spring boot中PropertySource注解的使用方法詳解
這篇文章主要給大家介紹了關(guān)于Spring boot中PropertySource注解的使用方法,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用Spring boot具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧。2017-12-12java 較大數(shù)據(jù)量取差集,list.removeAll性能優(yōu)化詳解
這篇文章主要介紹了java 較大數(shù)據(jù)量取差集,list.removeAll性能優(yōu)化詳解,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-09-09JavaWeb中轉(zhuǎn)發(fā)與重定向的區(qū)別小結(jié)
轉(zhuǎn)發(fā)和重定向是JavaWeb中常用的兩種頁面跳轉(zhuǎn)方式,它們在實(shí)現(xiàn)上有一些區(qū)別,本文主要介紹了JavaWeb中轉(zhuǎn)發(fā)與重定向的區(qū)別小結(jié),具有一定的參考價(jià)值,感興趣的可以了解一下2023-10-10