什么是直接量?直接量是指:在程序中,通過源代碼直接指定的值。eg:int personId = 8080 ;String name = "fancy" ; 對于 java 中的字符串直接量,JVM 會使用一個字符串駐留池來緩存它們。一般情況下,字符串駐留池中的字符串對象不會被 GC (Garbage Collection,垃圾回收) 所回收,當再次使用字符串駐留池中已有的字符串對象時候,無需再次創建它,而直接使它的引用變量指向字符串駐留池中已有的字符串對象。 String 基礎: String 類代表字符串。字符串是常量,它們的值在創建之后是不能再被更改的。在 java 中除了 synchronized之外,不可變的類也是線程安全的,因此,String 類本身也是線程安全的。String 類的實例對象其實是可以被共享的。示例代碼: 12 String name = "fancy"; // @13 String nick = "fancydeepin"; // @24 name = nick;5 System.out.println(name); // export:fancydeepin6 結果輸出 :fancydeepin這是怎么回事?不是說 String 是不可變的字符串嗎?怎么這里又變了?是這樣的,在這里 name 只是一個引用類型變量,并不是一個 String 對象,@1中創建了一個 "fancy" 的字符串對象,@2中創建了一個 "fancydeepin" 的字符串對象,name 引用 (就像一個指針) 剛開始是指向 "fancy" 對象,而后,name 又重新指向 "fancydeepin" 對象,在示例代碼中,整個過程只創建了兩個 String 對象 (不知道我這樣說你能不能理解,為什么是只創建了兩個 String 對象?而不是 1個、3個... @3),一個是 "fancy" 對象,另外一個是 "fancydeepin" 對象。而這兩個對象被創建出來后并沒有被改變過,之所以程序會輸出 fancydeepin,完全只是因為name 引用所指向的對象發生了改變。如果你是本著認真的態度看著我的貼子,細心的你,是否會留意到:當 name 引用重新指向另外一個對象的時候,那 name 之前引用的對象 ( "fancy" 對象 ) JVM 在底層會怎么處理它呢?是會立即來回收它來釋放系統資源嗎?答案是否定的。雖然這時候程序再也不訪問 "fancy" 這個對象,但 JVM 還是不會來回收它,它將在程序運行期間久駐內存,為什么會這樣呢?再往下說就扯到 java 的內存管理機制了,這里點到即止。在這里你可以簡單的將它理解成 "fancy" 對象被緩存了起來 ( 實際上也是因為被緩存了 )。字符串駐留池當比較兩個 String 對象時候,是應該用 "==" 呢?還是應該選擇 equals 呢?相信絕大部分人絕大多時候使用的都是選擇用 equals 方法。"==" 和 equals 的用法相信大家都很熟悉了,"==" 比較的是兩個對象的哈希碼值是否相等,而 equals 比較的是對象的內容是否一樣。而絕大部分時候我們比較兩個 String 對象的時候只是想比較它們的內容是否相等,這樣看來,只能選 equals 了,但真的是這樣嗎?答案是否定的。你一樣也可以用 "==" 來完成這樣的一件事情,而且 "==" 的效率無論如何都是要比使用 equals 的效率要高的,但前提是,需要使用字符串的駐留池,才能使用 "==" 來替代 equals 作比較。String 里面有個方法叫 intern(),執行效率很高,但也許你還不曾用過,下面是摘自API中 intern() 方法的描述:“當調用 intern 方法時,如果池已經包含一個等于此 String 對象的字符串(用 equals(Object) 方法確定),則返回池中的字符串。否則,將此 String 對象添加到池中,并返回此 String 對象的引用。 它遵循以下規則:對于任意兩個字符串 s 和 t,當且僅當 s.equals(t) 為 true 時,s.intern() == t.intern() 才為 true。 ”示例代碼: 1 2 String name = new String("fancy"); 3 4 if(name == "fancy") { // false 5 System.out.println("equals 1"); 6 }else { 7 System.out.println("not equals 1"); // Be printed 8 } 9 10 name = name.intern(); // 將字符串添加到駐留池11 12 if(name == "fancy") { // true13 System.out.println("equals 2"); // Be printed14 }else {15 System.out.println("not equals 2");16 }17 輸出結果: 12not equals 13equals 24 由上面的示例代碼可以看到,字符串駐留池的使用是非常簡單的,池中的對象可以被共享,只要你將字符串添加到池中,就能夠直接使用"==" 來比較兩個對象,而不是只能使用 equals 來作比較。將字符串添加到駐留池來使用 "==" 作比較的方式要比直接使用 equals 效率要高些。再論 String、StringBuffer 和 StringBuilder 由 synchronized 修飾的方法可以保證方法的線程安全,但是會降低該方法的執行效率; 翻開 API,很容易就能知道:StringBuffer 是線程安全的可變字符序列,StringBuilder 是一個可變的字符序列,是線程不安全的;網上說的所謂的使用 StringBuffer 的效率更高更好,這已經不合時宜,這是 java 1.5 之前的版本的說法,早過時了現在!!現在是反過來了,由于 StringBuilder 不是線程安全的,StringBuilder 效率會比 StringBuffer 效率更高一些。你可以不相信我說的,但你總該相信程序跑出來的結果吧,下面是示例代碼: 1 2 StringBuffer buffer = new StringBuffer(); 3 StringBuilder builder = new StringBuilder(); 4 int COUNT = 10; // 測試 COUNT 趟 5 final int N = 100000; // 每趟操作 N 次 6 double beginTime, costTime; // 每趟開始時間和耗費時間 7 double bufferTotalTime = 0.0D, buliderTotalTime = 0.0D; // StringBuffer 和 StringBuilder 測試 COUNT 趟的總耗時 8 while(COUNT -- > -1) { 9 // 也可以測試每趟都創建一個新的對象,這樣 StringBuilder 效率比 StringBuffer 的效率變得更明顯了10 /**11 StringBuffer buffer = new StringBuffer();12 StringBuilder builder = new StringBuilder();13 */14 System.out.println("----------------------------------<" + (COUNT + 1) + ">");15 beginTime = System.currentTimeMillis();16 for(int i = 0; i < N; i++) {17 buffer.append(i);18 buffer.length();19 }20 costTime = System.currentTimeMillis() - beginTime;21 bufferTotalTime += costTime;22 System.out.println("StringBuffer 費時: --->> " + costTime);23 beginTime = System.currentTimeMillis();24 for(int i = 0; i < N; i++) {25 builder.append(i);26 builder.length();27 }28 costTime = System.currentTimeMillis() - beginTime;29 buliderTotalTime += costTime;30 System.out.println("StringBuilder 費時: --->> " + costTime);31 System.out.println("----------------------------------<" + (COUNT + 1) + ">");32 }33 System.out.println("bufferTotalTime / buliderTotalTime = " + (bufferTotalTime / buliderTotalTime));34 后臺輸出結果: 1 2----------------------------------<10> 3StringBuffer 費時: --->> 32.0 4StringBuilder 費時: --->> 16.0 5----------------------------------<10> 6----------------------------------<9> 7StringBuffer 費時: --->> 21.0 8StringBuilder 費時: --->> 15.0 9----------------------------------<9>10----------------------------------<8>11StringBuffer 費時: --->> 25.012StringBuilder 費時: --->> 35.013----------------------------------<8>14----------------------------------<7>15StringBuffer 費時: --->> 24.016StringBuilder 費時: --->> 8.017----------------------------------<7>18----------------------------------<6>19StringBuffer 費時: --->> 48.020StringBuilder 費時: --->> 38.021----------------------------------<6>22----------------------------------<5>23StringBuffer 費時: --->> 22.024StringBuilder 費時: --->> 8.025----------------------------------<5>26----------------------------------<4>27StringBuffer 費時: --->> 23.028StringBuilder 費時: --->> 9.029----------------------------------<4>30----------------------------------<3>31StringBuffer 費時: --->> 25.032StringBuilder 費時: --->> 7.033----------------------------------<3>34----------------------------------<2>35StringBuffer 費時: --->> 23.036StringBuilder 費時: --->> 7.037----------------------------------<2>38----------------------------------<1>39StringBuffer 費時: --->> 78.040StringBuilder 費時: --->> 59.041----------------------------------<1>42----------------------------------<0>43StringBuffer 費時: --->> 21.044StringBuilder 費時: --->> 11.045----------------------------------<0>46bufferTotalTime / buliderTotalTime = 1.605633802816901547 StringBuffer 在測試中平均耗時是 StringBuilder 的 1.6 倍以上,再測多次,都是 1.6 倍以上。StringBuffer 和 StringBuilder 的性能孰更加優,一眼明了。最后,如果你想知道 @3 (在上面我已經用紅色粗體標出) 的結果,不妨說一下:eg:String mail = "fancydeepin" + "@" + "yeah.net";來,一起來看一下上面的這條語句,想一下,這條語句將會創建幾個 String 的對象呢?1個? 2個? 3個? 4個? 5個? ... ...也許你會認為是4個,它們分別是:"fancydeepin"、"@"、"yeah.net"、"fancydeepin@yeah.net"也許你會認為是5個,它們分別是:"fancydeepin"、"@"、"yeah.net"、"fancydeepin@"、"fancydeepin@yeah.net"也許 ... ...但實際上,這條語句只創建了一個 String 對象!為什么會這樣呢?原因很簡單,這是因為,mail 在 編譯的時候其值就已經確定,它就是 "fancydeepin@yeah.net" 。當程序處于運行期間且當上面的這條語句被執行到的時候,那么 mail 所引用的對象就會被創建,而 mail 的值由于在編譯的時候已經確定它是 "fancydeepin@yeah.net" ,所以最終只有一個 String 對象被創建出來,而這個對象就是 "fancydeepin@yeah.net" 對象。這樣解釋都能夠理解了吧?真的理解了嗎?是真的理解才好,不妨再來看一個:eg:String mail = new String("fancydeepin@yeah.net");這回又創建了幾個對象呢?答案是2個。為什么不是1個了呢?2個又是哪2個呢?可以很肯定的告訴你,它們分別是: "fancydeepin@yeah.net"、new String()這是因為,這回 mail 在編譯的時候它的值是還不能夠確定的,編譯只是將源代碼翻譯成字節碼,程序還并沒有跑起來,還 new 不了對象,所以在編譯完成之后,mail 的值是還不能夠確定的。當程序處于運行期間且當上面的這條語句被執行到的時候,這時候才開始去確定 mail 的引用對象,首先,"fancydeepin@yeah.net" 對象會被創建,之后,再執行 new String(),所以這條語句最后實際上是創建了 2個 String 對象。
String 類代表字符串。字符串是常量,它們的值在創建之后是不能再被更改的。在 java 中除了 synchronized之外,不可變的類也是線程安全的,因此,String 類本身也是線程安全的。String 類的實例對象其實是可以被共享的。示例代碼:
String
結果輸出 :fancydeepin這是怎么回事?不是說 String 是不可變的字符串嗎?怎么這里又變了?是這樣的,在這里 name 只是一個引用類型變量,并不是一個 String 對象,@1中創建了一個 "fancy" 的字符串對象,@2中創建了一個 "fancydeepin" 的字符串對象,name 引用 (就像一個指針) 剛開始是指向 "fancy" 對象,而后,name 又重新指向 "fancydeepin" 對象,在示例代碼中,整個過程只創建了兩個 String 對象 (不知道我這樣說你能不能理解,為什么是只創建了兩個 String 對象?而不是 1個、3個... @3),一個是 "fancy" 對象,另外一個是 "fancydeepin" 對象。而這兩個對象被創建出來后并沒有被改變過,之所以程序會輸出 fancydeepin,完全只是因為name 引用所指向的對象發生了改變。如果你是本著認真的態度看著我的貼子,細心的你,是否會留意到:當 name 引用重新指向另外一個對象的時候,那 name 之前引用的對象 ( "fancy" 對象 ) JVM 在底層會怎么處理它呢?是會立即來回收它來釋放系統資源嗎?答案是否定的。雖然這時候程序再也不訪問 "fancy" 這個對象,但 JVM 還是不會來回收它,它將在程序運行期間久駐內存,為什么會這樣呢?再往下說就扯到 java 的內存管理機制了,這里點到即止。在這里你可以簡單的將它理解成 "fancy" 對象被緩存了起來 ( 實際上也是因為被緩存了 )。字符串駐留池當比較兩個 String 對象時候,是應該用 "==" 呢?還是應該選擇 equals 呢?相信絕大部分人絕大多時候使用的都是選擇用 equals 方法。"==" 和 equals 的用法相信大家都很熟悉了,"==" 比較的是兩個對象的哈希碼值是否相等,而 equals 比較的是對象的內容是否一樣。而絕大部分時候我們比較兩個 String 對象的時候只是想比較它們的內容是否相等,這樣看來,只能選 equals 了,但真的是這樣嗎?答案是否定的。你一樣也可以用 "==" 來完成這樣的一件事情,而且 "==" 的效率無論如何都是要比使用 equals 的效率要高的,但前提是,需要使用字符串的駐留池,才能使用 "==" 來替代 equals 作比較。String 里面有個方法叫 intern(),執行效率很高,但也許你還不曾用過,下面是摘自API中 intern() 方法的描述:“當調用 intern 方法時,如果池已經包含一個等于此 String 對象的字符串(用 equals(Object) 方法確定),則返回池中的字符串。否則,將此 String 對象添加到池中,并返回此 String 對象的引用。 它遵循以下規則:對于任意兩個字符串 s 和 t,當且僅當 s.equals(t) 為 true 時,s.intern() == t.intern() 才為 true。 ”示例代碼:
equals(Object)
s
t
s.equals(t)
true
s.intern() == t.intern()
tr
ue
輸出結果:
由上面的示例代碼可以看到,字符串駐留池的使用是非常簡單的,池中的對象可以被共享,只要你將字符串添加到池中,就能夠直接使用"==" 來比較兩個對象,而不是只能使用 equals 來作比較。將字符串添加到駐留池來使用 "==" 作比較的方式要比直接使用 equals 效率要高些。再論 String、StringBuffer 和 StringBuilder
由 synchronized 修飾的方法可以保證方法的線程安全,但是會降低該方法的執行效率;
翻開 API,很容易就能知道:StringBuffer 是線程安全的可變字符序列,StringBuilder 是一個可變的字符序列,是線程不安全的;網上說的所謂的使用 StringBuffer 的效率更高更好,這已經不合時宜,這是 java 1.5 之前的版本的說法,早過時了現在!!現在是反過來了,由于 StringBuilder 不是線程安全的,StringBuilder 效率會比 StringBuffer 效率更高一些。你可以不相信我說的,但你總該相信程序跑出來的結果吧,下面是示例代碼:
后臺輸出結果:
StringBuffer 在測試中平均耗時是 StringBuilder 的 1.6 倍以上,再測多次,都是 1.6 倍以上。StringBuffer 和 StringBuilder 的性能孰更加優,一眼明了。最后,如果你想知道 @3 (在上面我已經用紅色粗體標出) 的結果,不妨說一下:eg:String mail = "fancydeepin" + "@" + "yeah.net";來,一起來看一下上面的這條語句,想一下,這條語句將會創建幾個 String 的對象呢?1個? 2個? 3個? 4個? 5個? ... ...也許你會認為是4個,它們分別是:"fancydeepin"、"@"、"yeah.net"、"fancydeepin@yeah.net"也許你會認為是5個,它們分別是:"fancydeepin"、"@"、"yeah.net"、"fancydeepin@"、"fancydeepin@yeah.net"也許 ... ...但實際上,這條語句只創建了一個 String 對象!為什么會這樣呢?原因很簡單,這是因為,mail 在 編譯的時候其值就已經確定,它就是 "fancydeepin@yeah.net" 。當程序處于運行期間且當上面的這條語句被執行到的時候,那么 mail 所引用的對象就會被創建,而 mail 的值由于在編譯的時候已經確定它是 "fancydeepin@yeah.net" ,所以最終只有一個 String 對象被創建出來,而這個對象就是 "fancydeepin@yeah.net" 對象。這樣解釋都能夠理解了吧?真的理解了嗎?是真的理解才好,不妨再來看一個:eg:String mail = new String("fancydeepin@yeah.net");這回又創建了幾個對象呢?答案是2個。為什么不是1個了呢?2個又是哪2個呢?可以很肯定的告訴你,它們分別是: "fancydeepin@yeah.net"、new String()這是因為,這回 mail 在編譯的時候它的值是還不能夠確定的,編譯只是將源代碼翻譯成字節碼,程序還并沒有跑起來,還 new 不了對象,所以在編譯完成之后,mail 的值是還不能夠確定的。當程序處于運行期間且當上面的這條語句被執行到的時候,這時候才開始去確定 mail 的引用對象,首先,"fancydeepin@yeah.net" 對象會被創建,之后,再執行 new String(),所以這條語句最后實際上是創建了 2個 String 對象。
個人主頁
beanutil
jutil
jexcel
orc