1. 程式人生 > >媽媽再也不用擔心我的面試之String類詳解

媽媽再也不用擔心我的面試之String類詳解

其實在java中String並不能算是一個基本型別,迴歸到String的本質其實在jdk1.8以前他是一個final修飾的char陣列,1.9以後他是一個final修飾的byte陣列;由開發者將其封裝成String類;其實我們也可以從程式碼中來證明String是一個類的事實:

public class String1 {
	public static void main(String[] args) {
		String string = "sss";
		System.out.println("sss".equals(string));
	}
}
true

這裡我們可以看到  "sss" 這個常量可以使用equals方法進行物件相等這個判斷,所以我們可以得出結論 沒有字串這個常量,有的只有String類的匿名物件。

這裡使用equals我們有一個小技巧,也就是把字串常量寫在前面:

public class String1 {
	public static void main(String[] args) {
		String input = null;   //假設是一個輸入
		System.out.println(input.equals("sss"));
	}
}
Exception in thread "main" java.lang.NullPointerException
	at String1.main(String1.java:5)

這裡我們使用者並沒有輸出,這樣我們在進行比較時候就會報錯, 但是如果我們

public class String1 {
	public static void main(String[] args) {
		String input = null;   //假設是一個輸入
		System.out.println("sss".equals(input));
	}
}

將字串寫在前面,我們可以通過equals提供一個可以迴避null的判斷來避免錯誤,字串是一個匿名物件,只要是物件就會開闢堆記憶體空間,所以不會報錯。

現在我們來解釋一下字串的比較

我們先來看一下int型別的 == 判斷

public class String1 {
	public static void main(String[] args) {
		int x = 10;
		int y = 10;
		System.out.println(x == y);
	}
}

這裡程式碼是對基本型別進行判斷。但是如果我們使用 == 進行String類的比較呢?

public class String1 {
	public static void main(String[] args) {
		String str1 = "ss";
		String str2 = new String("ss");
		System.out.println(str1 == str2);
	}
}
false

首先我們避開程式碼不談,我們先來說一下這個new, new的功能其實就是在記憶體中開闢堆記憶體空間,所以說str2是重新開闢了一塊記憶體空間

所以說我們可以得出一個結論

“==” 用作數值的比較,但是如果用作物件的比較上則比較的記憶體的地址數值

現在我們就像判斷兩個物件的比較該怎麼辦。用equals這個類提供的方法,來直接對字串進行比較。

public class String1 {
	public static void main(String[] args) {
		String str1 = "ss";
		String str2 = new String("ss");
		System.out.println(str1.equals(str2));
	}
}
true

下面我們在繼續看一段程式碼

public class String1 {
    public static void main(String[] args) {
        String str1 = "sss";
        String str2 = "sss";
        System.out.println(str1 == str2);
    }
}
true

這裡我們發現執行結果返回的是true,所以我們可以判斷這裡指向的是他同一塊堆記憶體空間

主要原因是java底層提供一個專門的字串池(字串陣列)

str1會首先在在這個字串池中開闢一塊 "sss" 的堆記憶體空間

這時候我們再有一個str2的時候 他會優先查詢池 , 如果池中有這個資料則會優先使用池中資料,

如果沒有,則會在池中在開闢記憶體空間

對於字串而言在池中實現自動儲存,可以提升操作效能

public class String1 {
    public static void main(String[] args) {
        String str1 = new String("sss");
    }
}

現在我們來看一下之前這段程式碼。基於我們上面的分析來看。"sss"其實就是一個匿名物件開闢一塊記憶體空間, 但是我們的關鍵字new的功能也會開闢一塊堆記憶體空間,我們只會使用一塊記憶體空間,所以由字串常量所定義的匿名物件就會成為垃圾空間。

總結:我們使用

public class String1 {
    public static void main(String[] args) {
        String str1 = "sss";
    }
}

這種方式來進行會相對節約一部分記憶體的使用

接下來讓我們再次蹂躪我們之前的程式碼

public class String1 {
    public static void main(String[] args) {
        String str1 = "sss";
        String str2 = new String("sss");
    }
}

綜合來看我們的str1是使用我們java實現的字串池(也是堆記憶體)來進行儲存

str2 我們是使用new開闢的堆記憶體空間來儲存,

所以說我們的執行結果就是false

public class String1 {
    public static void main(String[] args) {
        String str1 = "sss";
        String str2 = new String("sss");
        System.out.println(str1 == str2);
    }
}

綜合以上就是我瞭解的String方面的問題

==============================================================

補充一個Integer型別的== 判斷

public class String1 {
    public static void main(String[] args) {
        Integer a = 10;
        Integer  a1 = 10;
        Integer b = 200;
        Integer b1 = 200;
        System.out.println(a == a1);
        System.out.println(b == b1);

    }
}
true
false

因為Integer : -127 +127 之前a a1 的值在這個區間 原始碼中Integer的區間定義是通過快取實現 ,b b1的比較直接從快取中取出,所以相同

但是b b1不在這個區間所以需要重新開闢不同的地址儲存,所以導致不同