1. 程式人生 > >java String物件總結

java String物件總結

String是一個物件,不是一個基本資料型別,預設值是null(因為物件的預設值是null)
String實際上是用字元陣列儲存的,這一點可以在原始碼中體現
1. String 建立方式

String ok1 = new String("ok");
String ok2 = "ok"

這裡寫圖片描述
第一種方式String ok1=new String(“ok”):首先會在堆記憶體申請一塊記憶體儲存字串ok,ok1指向其記憶體塊物件。同時還會檢查字串常量池中是否含有ok字串,若沒有則新增ok到字串常量池中。所以 new String()可能會建立兩個物件.
第二種方式`String ok2=“ok”: 先檢查字串常量池中是否含有ok字串,如果有則直接指向, 沒有則在字串常量池新增ok字串並指向它.所以這種方法最多建立一個物件,有可能不建立物件

2. 匹配方式
常量池是在java用於儲存在編譯時已經確定的,已經編譯的class檔案的一份資料
字串對比,看是否相等,有兩種方式:==和equals
比較類中的數值是否相等使用equals(),比較兩個包裝類的引用是否指向同一個物件時用==
第一種方式:==
1)java程式碼:
String ok = "ok"; String ok1 = new String("ok"); ok == ok1 (false)
原因:ok指向的是常量池中的物件,ok1指向的是堆記憶體中的物件,而且new的字串在編譯器是無法確定的
2)java程式碼:
String ok = "apple1"; String ok1 = "apple" + 1; ok == ok1 (true)


原因:編譯期ok1和ok都是確定的,ok和ok1都指向的是常量池裡面的字串apple1
3)java程式碼:
String ok = "apple1"; int temp = 1;String ok1 = "apple" + temp;ok==ok1(false)
原因:編譯期間ok1不是確定的(ok1含有變數),ok是確定的(指向常量池中的物件),所以不是指向同一個物件
4) java程式碼:
String ok = "apple1"; final int temp = 1; String ok1 = "apple"+temp; ok == ok1 (true)
原因:ok1是確定的了,因為temp能在編譯器確定
5) java程式碼:

public static void main(String[] args) {    
    String ok="apple1";  
    final int temp=getTemp();  
    String ok1="apple"+temp;  
    System.out.println(ok==ok1);//false       
}
public static int getTemp()  
{  
  return 1;  
} 

原因:ok1編譯時無法確定,需要執行程式碼獲得temp

3. 擴充套件常量池方式:intern()
intern()是擴充常量池的一個方法,當一個String例項str呼叫intern()方法時,java會檢查常量池中是否有相同的字串,如果有則返回其引用,如果沒有則在常量池中增加一個str字串並返回它的引用。

String ok="apple";  
String ok1=new String("apple");  
System.out.println(ok==ok1);//false  
ok1=ok.intern();//獲取常量池ok的引用  
System.out.println(ok==ok1);//true--指向同一個物件

4. 常量池
字串:其物件的引用都是儲存在棧中的,如果是編譯期已經建立好(直接用雙引號定義的)的就儲存在常量池中,如果是執行期(new出來的)才能確定的就儲存在堆中。對於equals相等的字串,在常量池中永遠只有一份,在堆中有多份。
java程式碼:

String s1 = "china";  
String s2 = "china";  
String s3 = "china";  
String ss1 = new String("china");  
String ss2 = new String("china");  
String ss3 = new String("china"); 

這裡寫圖片描述
對於基礎型別的變數和常量:變數和引用儲存在棧中,常量儲存在常量池中。

int i1 = 9;  
int i2 = 9;  
int i3 = 9;   
public static final int INT1 = 9;  
public static final int INT2 = 9;  
public static final int INT3 = 9;  

這裡寫圖片描述
對於成員變數和區域性變數:成員變數就是方法外部,類的內部定義的變數;區域性變數就是方法或語句塊內部定義的變數。區域性變數必須初始化。
形式引數是區域性變數,區域性變數的資料存在於棧記憶體中。棧記憶體中的區域性變數隨著方法的消失而消失。
成員變數儲存在堆中的物件裡面,由垃圾回收器負責回收。

class BirthDate {  
    private int day;  
    private int month;  
    private int year;      
    public BirthDate(int d, int m, int y) {  
        day = d;   
        month = m;   
        year = y;  
    }  
    省略get,set方法………  
}  
public class Test{  
    public static void main(String args[]){  
int date = 9;  
        Test test = new Test();        
           test.change(date);   
        BirthDate d1= new BirthDate(7,7,1970);         
    }    

    public void change1(int i){  
        i = 1234;  
    }  

這裡寫圖片描述
對於以上這段程式碼,date為區域性變數,i,d,m,y都是形參為區域性變數,day,month,year為成員變數。下面分析一下程式碼執行時候的變化:
(1). main方法開始執行:int date = 9;
date區域性變數,基礎型別,引用和值都存在棧中。
2). Test test = new Test();
test為物件引用,存在棧中,物件(new Test())存在堆中。
3). test.change(date);
i為區域性變數,引用和值存在棧中。當方法change執行完成後,i就會從棧中消失。
4). BirthDate d1= new BirthDate(7,7,1970);
d1為物件引用,存在棧中,物件(new BirthDate())存在堆中,其中d,m,y為區域性變數儲存在棧中,且它們的型別為基礎型別,因此它們的資料也儲存在棧中。day,month,year為成員變數,它們儲存在堆中(new BirthDate()裡面)。當BirthDate構造方法執行完之後,d,m,y將從棧中消失。
5).main方法執行完之後,date變數,test,d1引用將從棧中消失,new Test(),new BirthDate()將等待垃圾回收。

6. String 的常用方法

String類具有immutable(不可改變)性質,當String變數需要經常變化的時候,會產生很多變數值,應該考慮使用StringBuffer提高效率,在開發的時候,注意String的建立方法。

7. == 與 equals
String 是個物件,要對比兩個不同的String物件的值是否相同明顯的要用到 equals() 這個方法可是如果程式裡面有那麼多的String物件,有那麼多次的要用到 equals ,哦,天哪,真慢啊更好的辦法:把所有的String都intern()到緩衝池去吧最好在用到new的時候就進行這個操作String s2 = new String(“Monday”).intern();嗯,大家都在水池裡泡著了嗎?哈哈現在我可以無所顧忌的用 == 來比較 String 物件的值了真是爽啊,又快又方便!

例程1:
class Str { 
    public static void main(String[] args) { 
        String s = "Hi!"; 
        String t = "Hi!"; 
        if (s == t) 
            System.out.println("equals"); 
        else 
             System.out.println("not equals"); 
    } 
} //equals
例程2:
class Str { 
    public static void main(String[] args) { 
        String s = "HELLO"; 
        String t = s.toUpperCase(); 
        if (s == t) 
            System.out.println("equals"); 
        else 
            System.out.println("not equals"); 
    } 
} //equals

class Str2 { 
    public static void main(String[] args) { 
        String s = "Hello"; 
        String t = s.toUpperCase(); 
        if (s == t) 
            System.out.println("equals"); 
        else 
            System.out.println("not equals"); 
    } 
} // not equals

你瞭解 String 嗎?解讀 String 的 API ,可以看到:toUpperCase() 和 toLowerCase() 方法返回一個新的String物件,它將原字串表示字串的大寫或小寫形勢;但是要注意:如果原字串本身就是大寫形式或小寫形式,那麼返回原始物件。
(1) charAt(int n) 返回字串內n位置的字元,第一個字元位置為0,最後一個字元的位置為length()-1,訪 問錯誤的位置會扔出一塊大磚頭:StringIndexOutOfBoundsException 真夠大的
(2) concat(String str) 在原物件之後連線一個 str ,但是返回一個新的 String 物件
(3) EqualsIgnoreCase(String str) 忽略大小寫的 equals 方法這個方法的實質是首先呼叫靜態字元方法toUpperCase() 或者 toLowerCase() 將對比的兩個字元轉換,然後進行 == 運算
(4) trim() 返回一個新的物件,它將原物件的開頭和結尾的空白字元切掉同樣的,如果結果與原物件沒有差別,則返回原物件
(5) toString() String 類也有 toString() 方法嗎?真是一個有趣的問題,可是如果沒有它,你的 String 物件說不定真的不能用在System.out.println() 裡面啊小心,它返回物件自己String 類還有很多其他方法,掌握他們會帶來很多方便也會有很多困惑,所以堅持原則,是最關鍵的。
目前String看到的就是這些了,之後會再更新的