- 說出下面程序的輸出
class StringEqualTest { public static void main(String[] args) { String s1 = "Programming";
String s2 = new String("Programming");
String s3 = "Program" + "ming";
String s4=new String(s2);
String s5 = "Programming";
System.out.println(s1 == s2);//false
System.out.println(s4 == s2);//false
System.out.println(s1 == s3);//true
System.out.println(s1 == s1.intern());//true } }
解釋:
在此引入常量池這個概念:
常量池(constant pool)指的是在編譯期被確定,並被保存在已編譯的.class文件中的一些數據。它包括了關於類、方法、接口等中的常量,也包括字符串常量
首先,我們要知道Java會確保一個字符串常量只有一個拷貝。
因為例子中的s1和s3中的”
Programming
”都
是字
符串常量,它們在編譯期就被確定了,所以s1==s3為true;而”Program”和”ming”也都是字符 串常量,當一個字符串由多個字符串常量連接而成時,它自己肯定也是字符串常量,所以s3也同樣在編譯期就被解析為一個字符串常量,所以s3也是常量池中 ”kvill”的一個引用。
所以我們得出s5==s1==s2;
用new String() 創建的字符串不是常量,不能在編譯期就確定,所以new String() 創建的字符串不放入常量池中,它們有自己的地址空間。
所以有s2!=s4
String對象的intern方法會得到字符串對象在常量池中對應的版本的引用(如果常量池中有一個字符串與String對象的equals結果是true),如果常量池中沒有對應的字符串,則該字符串將被添加到常量池中,然后返回常量池中字符串的引用。
再補充介紹一點:存在於.class文件中的常量池,在運行期被JVM裝載,並且可以擴充。String的intern()方法就是擴充常量池的一個 方法;當一個String實例str調用intern()方法時,Java查找常量池中是否有相同Unicode的字符串常量,如果有,則返回其的引用, 如果沒有,則在常量池中增加一個Unicode等於str的字符串並返回它的引用;
案例
String s0= “kvill”; String s1=new String(”kvill”); String s2=new String(“kvill”); System.out.println( s0==s1 ); System.out.println( “**********” ); s1.intern(); s2=s2.intern(); //把常量池中“kvill”的引用賦給s2 System.out.println( s0==s1); System.out.println( s0==s1.intern() ); System.out.println( s0==s2 ); 結果為: false ********** false //雖然執行了s1.intern(),但它的返回值沒有賦給s1 true //說明s1.intern()返回的是常量池中”kvill”的引用 true
關於equals()和==:
這個對於String簡單來說就是比較兩字符串的Unicode序列是否相當,如果相等返回true;String類已經重寫過了equals方法。
。而==是比較兩字符串的地址是否相同,也就是是否是同一個字符串的引用
而在符合數據類型中,則equals和==都是比較兩對象的地址是否相同,除非重寫equals,詳見hashcode與equals的區別。
- 使用equals方法比較兩個相同的StringBuffer對象
StringBuffer sb0=new StringBuffer("hello"); StringBuffer sb1=new StringBuffer("hello"); System.out.println(sb0==sb1); System.out.println(sb0.equals(sb1)); System.out.println(sb0.toString().equals(sb1.toString())); false false true
StringBuffer 類沒有重寫Object類下的equals方法,所以實質還是==比較,所以如果需要比較兩個StringBuffer對象是否相等則toString()方法轉為String。
.關於String是不可變的
這一說又要說很多,大家只要知道String的實例一旦生成就不會再改變了,比如說:String str=”kv”+”ill”+” “+”ans”;
就是有4個字符串常量,首先”kv”和”ill”生成了”kvill”存在內存中,然后”kvill”又和” “ 生成 ”kvill “存在內存中,最后又和生成了”kvill ans”;並把這個字符串的地址賦給了str,就是因為String的“不可變”產生了很多臨時變量,這也就是為什么建議用StringBuffer的原 因了,因為StringBuffer是可改變的。- 可不可以在分割字符串是使用多個分割符
String str="2012-05-25 13:24:16"; String[] s=str.split("-|:|\\s"); for(String temp:s){ System.out.print(temp+" "); } 2012 05 25 13 24 16
關鍵點就是在split()方法中使用多個分割符;其實split()方法里的分割符參數是一個正則表達式,所以可以使用或操作符(|)鏈接多個分割符,這樣在分割的時候就會按照所有的分割符對字符串進行分割了。\s表示空格,不過在字符串使用過程中還需要在\s之前添加轉義字符"\",否則會出現編譯錯誤。