Java中String的一點事

編程語言 Java虛擬機 技術 一個愛閒扯的Coder 2017-07-30

今天,記錄下Java中String的一點相關的知識,補足一下自己的知識儲備。

很多初學者可能會跟我一樣天真的認為String會是8大基本類型中的一種!這是完全錯誤的(手動滑稽自己)。為大家普及一下,8大基本數據類型:int、short、boolean、long、byte、char、float、double。就是這些,現在千萬要記住了!

再說String,為大家附上一張Java源碼中的String代碼圖。具體的還需要各位自己去查閱。

Java中String的一點事

我今天所說的知識自己學到的一小部分,大手勿噴。從源碼當中可以看見,String被final所修飾,很顯然,String是一個不能被繼承的類,同時也是一個被定義之後就不能修改的類。(是不是開始懷疑人生,自己以前修改的莫非是…)String對象代表的是一組不可以改變的Unicode字符序列,對它的任何一次修改,實際上是產生了一個新的對象,只不過你的引用是指向新的對象,你看不出來而已。然後Java的垃圾回收機制,將沒有被指向的對象進行回收(個人認為).

String s = “123”

String s1 = “123”

s和s1指向的都是內存中“123”所在的地址,他們本質上是相同的,只是引用的名字不一樣。就類似我給你取了一個外號,它跟你的名字一樣,都是代表你。但是如果使用的是new方法進行動態的創建的話,那麼就必須在對內存中開闢另外一塊區域,用來存新的對象。怎麼說呢,這就好比分身術,又出來一個跟你一模一樣的你(我也不知道比較是否恰當,敬請指正),但是現在一樣的名字,就不再是你了,因為你的分身又是一個新的對象了。

接下來,我們來說一說String的比較方法。記得我在Java的equals和==關係中說過,在沒有重寫equals方法的時候,== 和equals的效果是一樣的。所以,你動態分配和靜態分配的時候,兩者的地址發生了根本性的變化,不能再以老眼光來看了。下面舉個例子:

String s = “123”

String s1= “123”

String s2 = new String(“123”)

s和s1進行比較的時候,兩個引用指向的是同一個地址,而且字面量也是完全相同的,所以將會返回true;但是s或者s1跟s2進行比較的時候,兩個都會返回false。結果為什麼會這樣,想必大家都很清楚了。我今天說的是下面這幾種情況:

package test;

public class TestString {

public static void main(String[] args) {

String m ="a";

String a = "b";

String me = "a"+"b";

String all = "ab";

String mess = m + a ;

System.out.println(me ==all);

System.out.println(me == mess);

System.out.println(all == mess);

}

}

大家可以猜測一下,這個的結果是什麼。

在進行這幾個值的比較的時候,只有me == all 返回的是true,然後mess 與me 、all進行比較的時候都是返回的false。這是因為,編譯器在編譯期間自動就將常量進行了拼接,將其組成一個字符串並且將這個常量放入常量池當中。但是存在引用的時候,編譯器是不能夠進行+操作的。因為+操作是在運行期間進行的,所以引用進行+操作的時候會重新為拼接後的字符串創建一個新的對象,然後再進行比較。(所謂的編譯,就是你在寫代碼的時候鍵入的源代碼編譯器會主動幫你檢測,生成一類文件,然後交由JVM(自己的理解))。但是如果這個引用是使用final修飾的話(但是值一定要是已知的,比如是賦值的常量,不能使用類似方法去獲取),那麼就類似常量進行拼接。

同時,在進行字符串定義的時候,系統會主動檢測常量池中是否有類似的對象,如果有,引用則直接指向這個棧中的地址;如果沒有,那麼將新建一個對象放入其中。如果使用的是new,那麼將指向堆中的這個對象。(另外基本數據類型我只測試了int,其他的還希望你們自己去測試,以便驗證)。或許還有很多的初學者沒有弄明白編譯和運行到底怎麼區分,下面我說一下自己的拙見:我認為編譯其實在我們敲代碼的過程中就在進行,正如我們在編譯器中鍵入代碼一樣,編譯器自動就會為我們檢測,這個時候我認為就是在編譯。然後運行,就是我們使用運行命令運行的時候,那個時候將會做更加深度的計算以及解讀。

好了,今天就說到這裡,希望自己加油!也希望你們加油!

相關推薦

推薦中...