雙重檢查鎖 單例模式(懶漢模式)
阿新 • • 發佈:2021-01-20
一、字串比較相等
- “==” 比較地址是否相等
String str1 = "Hello";
String str2 = "Hello";
System.out.println(str1 == str2);
// 執行結果
true
String str1 = new String("Hello");
String str2 = new String("Hello");
System.out.println(str1 == str2);
// 執行結果
false
程式碼1的記憶體佈局
程式碼2的記憶體佈局
- “equals” 比較內容是否相等
String str = new String("Hello");
System.out.println("Hello".equals(str));
// 執行結果
true
二、字串常量池
String類的兩種例項化操作,直接賦值和 new 一個新的 String
a)直接賦值
String str1 = "hello" ; String str2 = "hello" ; String str3 = "hello" ; System.out.println(str1 == str2); // true System.out.println(str1 == str3); // true System.out.println(str2 == str3); // true
在JVM底層自動維護了一個物件池(字串常量池),如果採用直接賦值的模式進行String類的物件例項化操作,那麼該例項化物件(字串內容)將自動儲存到這個物件池之中。如果下次繼續使用直接賦值的模式宣告String類物件,此時物件池之中若有指定內容,將直接進行引用;若沒有,則開闢新的字串物件而後將其儲存在物件池之中以供下次使用。
b)採用構造方法
String str = new String("hello") ;
這樣做有兩個缺點:
1. 如果使用String構造方法就會開闢兩塊堆記憶體空間,並且其中一塊堆記憶體將成為垃圾空間(字串常量 "hello" 也是一個匿名物件, 用了一次之後就不再使用了, 就成為垃圾空間, 會被 JVM 自動回收掉)。
可以使用 String 的 intern 方法手動把 String 物件加入到字串常量池中
呼叫intern方法,就會拿著當前字串的內容在字串常量池中找,看是否已經存在於池中,若存在,直接返回池中的地址;若不存在,則把當前字串內容存到常量池中,再返回池中地址。
// 該字串常量並沒有儲存在物件池之中
String str1 = new String("hello") ;
String str2 = "hello" ;
System.out.println(str1 == str2);
// 執行結果
false
//使用 String 的 intern 方法手動把 String 物件加入到字串常量池中
String str1 = new String("hello").intern() ;
String str2 = "hello" ;
System.out.println(str1 == str2);
// 執行結果
true
一般採取直接賦值的方式建立 String 物件
三、字串不可變
字串是一種不可變物件,它的內容不可改變。所謂的修改其實是建立了新的物件,所指向的記憶體空間不變。
如果需要修改字串內容,可以使用"反射","反射" 這樣的操作可以破壞封裝,,訪問一個類內部的 private 成員。
String str = "Hello";
// 獲取 String 類中的 value 欄位. 這個 value 和 String 原始碼中的 value 是匹配的.
Field valueField = String.class.getDeclaredField("value");
// 將這個欄位的訪問屬性設為 true
valueField.setAccessible(true);
// 把 str 中的 value 屬性獲取到.
char[] value = (char[]) valueField.get(str);
// 修改 value 的值
value[0] = 'h';
System.out.println(str);
// 執行結果
hello