1. 程式人生 > >Java原始碼解析|String原始碼與常用方法

Java原始碼解析|String原始碼與常用方法

String原始碼與常用方法

1.栗子

程式碼:

public class JavaStringClass {
    
    public static void main(String[] args) {
        String s ="hello";
        s = "world"; //記憶體地址已經修改 原來地址上的值還是不變的
        String s2 = "hello"; //從常量值中找到並引用
        String s4 = new String("hello"); //new產生一個新的物件 不會從常量池中引用
        String s6 = "hel" + "lo";
        String s7 = new String("hel") + new String("lo");
        System.out.println(s == s2); //引用相等
        System.out.println(s2 == s4); //引用不相等
        System.out.println(s2.equals(s4)); //值相等 分析equals方法原始碼
        System.out.println(s2 == s6); //引用相等 使用相 常量相加 也是從常量池中找到引用
        System.out.println(s2 == s7); //引用不相等
        
        //開頭字母大寫
        System.out.println(s2.substring(0,1).toUpperCase() + s2.substring(1));
        
        System.out.println(s2);
    }
}

輸出:

2.String的不變性

2-1:字串常量池

String s ="hello";
String s2 = "hello";
System.out.println(s == s2); //true  說明引用相等(地址相等)

`s與s2引用相等即地址相等,原因是:Java把字串常量存入字串常量池

而 String s4 = new String("hello"); s4和 s2的值不相等,是因為new會產生一個新的物件,不會從字串常量池中找引用

2-2:String的不變性

`主要是因為 String 和儲存資料的 char 陣列,都被 final 關鍵字所修飾,所以是不可變的

如下圖所示:被final關鍵字修飾的變數(這裡是字元陣列),值不可以改變

所以當 String s ="hello"; s = “world”時,s的記憶體地址(s的引用物件)已經改變了,
說明產生了新的字串物件,已經不再指向字串常量池的“hello”,而是指向了“world”。

3.String重寫equal方法,判斷相等

1.先判斷 引用是否相等 this == object,地址引用相等說明指向同一個物件,那麼值肯定也相等了
2.再使用instanceof 判斷型別是否與String型別相等
3.最後逐個判斷 底層字元陣列中的每一個字元是否相等

public boolean equals(Object anObject) {
    // 判斷記憶體地址是否相同
    if (this == anObject) {
        return true;
    }
    // 待比較的物件是否是 String,如果不是 String,直接返回不相等
    if (anObject instanceof String) {
        String anotherString = (String)anObject;
        int n = value.length;
        // 兩個字串的長度是否相等,不等則直接返回不相等
        if (n == anotherString.value.length) {
            char v1[] = value;
            char v2[] = anotherString.value;
            int i = 0;
            // 依次比較每個字元是否相等,若有一個不等,直接返回不相等
            while (n-- != 0) {
                if (v1[i] != v2[i])
                    return false;
                i++;
            }
            return true;
        }
    }
    return false;
}

4.String常用的操作方法

4-1:字串擷取:
方法1:public String substring(int beginIndex, int endIndex) // beginIndex:開始位置,endIndex:結束位置;
方法2:public String substring(int beginIndex) //beginIndex:開始位置一直到到字串末尾結束位置
擷取原理:substring 方法的底層使用的是字元陣列範圍擷取的方法 :Arrays.copyOfRange(字元陣列,開始位置,結束位置)

4-2:字串大小寫:
小寫方法:String.toLowerCase() //小寫
大寫方法:String.toUpperCase()//大寫

上面兩種常用方法的綜合應用:將首字母小寫
有時候我們會通過 applicationContext.getBean(className); 這種方式得到 SpringBean,這時 className 必須是要滿足首字母小寫的

name.substring(0, 1).toLowerCase() name.substring(1);

4-3:字串替換、刪除

public void testReplace(){
  String str ="hello word !!";
  log.info("替換之前 :{}",str);
  str = str.replace('l','d');
  log.info("替換所有字元 :{}",str);
  str = str.replaceAll("d","l");
  log.info("替換全部 :{}",str);
  str = str.replaceFirst("l","");
  log.info("替換第一個 l :{}",str);
}
//輸出的結果是:
替換之前 :hello word !!
替換所有字元 :heddo word !!
替換全部 :hello worl !!
替換第一個 :helo worl !!

4-4:字串拆分

String s ="boo:and:foo";
// 我們對 s 進行了各種拆分,演示的程式碼和結果是:
s.split(":") 結果:["boo","and","foo"]
s.split(":",2) 結果:["boo","and:foo"]
s.split(":",5) 結果:["boo","and","foo"]
s.split(":",-2) 結果:["boo","and","foo"]
s.split("o") 結果:["b","",":and:f"]
s.split("o",2) 結果:["b","o:and:foo"]

但是會拆分出空值

String a =",a,,b,";
a.split(",") 結果:["","a","","b"]

使用google的Guava快速去除空值

String a =",a, ,  b  c ,";
// Splitter 是 Guava 提供的 API 
List<String> list = Splitter.on(',')
    .trimResults()// 去掉空格
    .omitEmptyStrings()// 去掉空值
    .splitToList(a);
log.info("Guava 去掉空格的分割方法:{}",JSON.toJSONString(list));
// 打印出的結果為:
["a","b  c"]

4-5:字串合併

合併我們使用 join 方法,此方法是靜態的,我們可以直接使用。
方法有兩個入參,引數一是合併的分隔符,引數二是合併的資料來源

不足:join不能連續合併(不能鏈式合併),無法過濾Join物件是List時的null值

解決辦法:使用Guava 提供的 API,Joiner快速合併

// 依次 join 多個字串,Joiner 是 Guava 提供的 API
Joiner joiner = Joiner.on(",").skipNulls();
String result = joiner.join("hello",null,"china");
log.info("依次 join 多個字串:{}",result);

List<String> list = Lists.newArrayList(new String[]{"hello","china",null});
log.info("自動刪除 list 中空值:{}",joiner.join(list));

// 輸出的結果為;
依次 join 多個字串:hello,china
自動刪除 list 中空值:hello,china