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看到的就是這些了,之後會再更新的