Java學習——String類
一、String的兩種例項化方式
1.直接賦值(用的最多,也最推薦)
2.通過構造方法
String str = "HelloWorld";//推薦使用
String str2 = new String("HelloWorld");
二、字串相等比較
如果現在有兩個int型變數,判斷其相等可以使用“==”完成。如果說現在在String類物件上使用“==”?
class Test{ public static void main(String[] args) { String str1 = "Hello"; String str = new String("Hello"); System.out.println(str == str1); } } //輸出false
現在兩個字串內容相同,而使用“==“得到的結果卻是false,說明兩個字串不同嘛。為什麼會這樣?
其實"=="本身是進行數值比較的,如果現在用於物件比較,那麼所比較的是兩個物件所儲存的記憶體地址數值,而並沒有比較物件的內容。在記憶體中就是這樣的:
那麼要想比較內容,則必須採用String類提供的equals方法。
class Test{ public static void main(String[] args) { String str1 = "Hello"; String str = new String("Hello"); System.out.println(str.equals(str1)); } } //輸出true
三、字串常量是String類的匿名物件。
簡單來說就是這樣
class Test{
public static void main(String[] args) {
String str = new String("Hello");
System.out.println("Hello".equals(str));
}
}
"Hello"本身就是一個物件,可以通過"."來呼叫String類中的方法。比如上面的"Hello".equals(str)。
tips:在進行指定內容比較時,將指定內容(字串常量)寫前面,避免空指標異常(NullPointerException)
String str = null;
System.out.println(str.equals("Hello"));
上面的程式碼中假設str要使用者輸入,而使用者沒有輸入,則一定會出現Exception in thread "main" java.lang.NullPointerException,即空指標異常。正確的寫法如下:
String str = null;
System.out.println("Hello".equals(str));
四、String的兩種例項化方式的比較
1.直接賦值法
看這樣一段程式碼
class Test{
public static void main(String[] args) {
String str1 = "hello" ;
String str2 = "hello" ;
String str3 = "hello" ;
System.out.println(str1 == str2); // true
System.out.println(str1 == str3); // true
System.out.println(str2 == str3); // true
}
}
/**輸出
* true
* true
* true
*/
記憶體分析
好像和前面說的不一樣啊,為什麼現在並沒有開闢新的堆記憶體空間呢?這是因為String類的設計使用了共享設計模式
在jvm底層自動維護一個字串物件池(物件陣列),如果採用直接賦值的模式進行String類的物件例項化操作,此物件將自動儲存到物件池中,如果下次繼續採用直接賦值的模式宣告String物件,先去物件池中找是否有指定內容,如果有,直接引用;如果沒有,開闢新的空間而後將其儲存到物件池中以供下次使用。
2.採用構造方法
String str = new String("hello") ;
通過分析可知,如果使用String構造方法就會開闢兩塊堆記憶體空間,並且其中一塊堆記憶體將成為垃圾空間。除了這
一缺點之外,也會對字串共享產生問題。
// 該字串常量並沒有儲存在物件池之中
String str1 = new String("hello") ;
String str2 = "hello" ;
System.out.println(str1 == str2); // false
這也就是為什麼"=="可以比較都是直接賦值的的字串而不能比較一個直接賦值一個由構造方法賦值的字串的原因
在String類中也提供了方法手動進行入池操作public String intern() ;
class Test{
public static void main(String[] args) {
String str1 = new String("hello").intern() ;
String str2 = "hello" ;
System.out.println(str1 == str2);
}
}
//輸出true
總結:
1. 直接賦值:只會開闢一塊堆記憶體空間,並且該字串物件可以自動儲存在物件池中以供下次使用。
2. 構造方法:會開闢兩塊堆記憶體空間,其中一塊成為垃圾空間,不會自動儲存在物件池中,可以使用intern()
方法手工入池。
五、字串常量不可變更
字串一旦定義不可改變。所有的語言對於字串的底層實現,都是字元陣列,陣列的最大缺陷就是長度固定。在定義字串常量時,它的內容不可改變。有人會說,我這樣寫不就是增加了字串的長度了嗎?
class Test{
public static void main(String[] args) {
String str = "hello" ;
str += "world";
System.out.println(str);
}
}
//輸出helloworld
我們分析一下,之前說了字串常量是String類的匿名物件,上面的程式碼中"world"就已經是一個物件了,在記憶體中已經分配了空間,進行“+”操作後,則記憶體又開闢了一個空間來存放"helloworld",然後將str指向這個空間。表面上看起來是str字串變長了,實際上是str的指向變更了。無論是“hello”還是“world”字串常量都沒有變更過。
可以發現字串上沒有發生任何變化,但是字串物件的引用一直在改變,而且會形成大量的垃圾空間。正是因為
String的特點,所以如下程式碼不應該在你的開發中出現:
String str = "hello" ;
for(int x = 0 ; x<1000 ; x++) {
str += x ;
}
System.out.println(str)
如果有很多使用者都使用了同樣的操作,那麼產生的垃圾數量就相當可觀了。
使用字串的原則
- 字串使用就採用直接賦值。
- 字串比較就使用equals()實現。
- 字串別改變太多。
六、字元與字串
字串就是一個字元陣列,所以在String類裡面支援有字元陣列轉換為字串以及字串變為字元的操作方法。
1.字元陣列轉為字串
class Test{
public static void main(String[] args) {
char[] c = new char[]{'h','e','l','l','o'};
String str = new String(c);
System.out.print(str);//hello
}
}
2.將字串按照索引轉換成單個字元
public char charAt(int index) :取得指定索引位置的字元
class Test{
public static void main(String[] args) {
String str = "Hello";
System.out.print(str.charAt(0));// H
}
}
3.將字串轉為字元陣列
public char[] toCharArray();
class Test{
public static void main(String[] args) {
String str = "Hello";
char[] c = str.toCharArray();
for (char temp:c){
System.out.print(temp + ",");//H,e,l,l,o,
}
}
}
七、位元組與字串
1.位元組陣列轉字串
class Test{
public static void main(String[] args) {
byte[] data = new byte[]{70,72,73,74,75};//字串轉位元組陣列
String str = new String(data);
System.out.print(str);//FHIJK
}
}
2.將部分位元組陣列中的內容轉成字串
class Test{
public static void main(String[] args) {
//String str = "Hello";
byte[] data = new byte[]{70,72,73,74,75};//字串轉位元組陣列
String str = new String(data,1,3);
System.out.print(str);//HIJ
}
}
3.字串轉位元組陣列
class Test{
public static void main(String[] args) {
String str = "Hello";
byte[] data = str.getBytes();//字串轉位元組陣列
for (byte temp : data) {
System.out.print(temp + ",");//72,101,108,108,111,
}
}
}
八、字串比較
equals()區分大小寫的比較
equalsIgnoreCase() 不區分大小寫的比較
public class Test {
public static void main(String[] args) {
String str1 = "hello";
String str2 = "HELLO";
System.out.println(str1.equals(str2));//false
System.out.println(str1.equalsIgnoreCase(str2));//true
}
}
2.比較兩個字串的關係
public int compareTo(String anotherString)
public class Test {
public static void main(String[] args) {
String str1 = "h";
String str2 = "H";
System.out.println(str1.compareTo(str2));//32
}
}
compareTo()的返回值有如下3種類型:
1. 相等:返回0.
2. 本字串小於目標字串:返回內容小於0
3. 本字串大於目標字串:返回內容大於0
通過分析可見這個返回值是2個字串ASCII碼的差值,而且從前向後比遇見第一個不同的字元就返回不會再往後進行,即
"abc".compareTo("ABC") 的返回值也是32
九、字串查詢——從一個完整的字串中判斷指定內容是否存在
1.判斷指定字串是否存在
public boolean contains(CharSequence s)
public class Test {
public static void main(String[] args) {
String str1 = "Hello World";
String str2 = "Hello";
System.out.println(str1.contains(str2));//true
}
}
2.判斷是否以指定字串開頭
public boolean startsWith(String prefix)
public boolean startsWith(String prefix, int toffset):從指定位置判斷是否以指定字串開頭
3.判斷是否以指定字串結尾
public boolean endsWith(String suffix)
public class Test {
public static void main(String[] args) {
String str1 = "Hello World";
String str2 = "Hello";
System.out.println(str1.startsWith(str2));//true
System.out.println(str1.startsWith("llo",2));//true
System.out.println(str1.endsWith("dd"));//false
}
}
十、字串替換
public String replaceAll(String regex, String replacement):替換所有的指定內容
public String replaceFirst(String regex, String replacement):替換首個內容
public class Test {
public static void main(String[] args) {
String str1 = "Hello World";
System.out.println(str1.replaceAll("l","*"));//He**o Wor*d
System.out.println(str1.replaceFirst("l","#"));//He#lo World
}
}
十一、字串拆分——可以將一個完整的字串按照指定的分隔符劃分為若干個子字串。
public String[] split(String regex):將字串全部拆分
public String[] split(String regex, int limit) :將字串拆分成陣列長度為limit的子字串陣列
注意:特殊字元需要使用“\\”轉義後拆分
eg:\\.
public class Test {
public static void main(String[] args) {
String str1 = "192###168#0#1";
for (String temp :
str1.split("#")) {
System.out.print(temp + ",");//192,,,168,0,1,
}
System.out.println();
for (String temp :
str1.split("#",2)) {
System.out.print(temp + ",");//192,##168#0#1,
}
}
}
多次拆分
public class Test {
public static void main(String[] args) {
String str = "張三:30|李四:40";
String[] temp = str.split("\\|");
for(int i = 0;i<temp.length;i++){
String name = temp[i].split(":")[0];
String age = temp[i].split(":")[1];
System.out.print("name:"+name);
System.out.println(" age:"+age);
}
}
}
/**輸出
* name:張三 age:30
* name:李四 age:40
*/
十二、字串擷取
public String substring(int beginIndex):從指定索引擷取到結尾
public String substring(int beginIndex, int endIndex):從指定索引擷取部分內容
public class Test {
public static void main(String[] args) {
String str = "Hello World";
System.out.println(str.substring(3));//lo World
System.out.println(str.substring(3,7));//lo W
}
}
十三、字串其他操作方法
1.去除字串左右空格
public String trim();
2.字串轉大小寫(全部大小寫)
public String toUpperCase();字串轉大寫
public String toLowerCase();字串轉小寫
例:把單詞首字母大寫
public class Test {
public static void main(String[] args) {
String str = "hello";
System.out.println(str.substring(0,1).toUpperCase() + str.substring(1));
//輸出Hello
}
}
3.判斷字串是否為空
public boolean isEmpty();(判斷“”,不判斷null)
判斷空字串完整寫法
if(str == null || str.isEmpty())
要先判斷str是否等於null,如果等於null後面的就不要判斷了,2句話不能寫反,如果str是null,先執行後面的會產生空指標異常