1. 程式人生 > 其它 >雙重檢查鎖 單例模式(懶漢模式)

雙重檢查鎖 單例模式(懶漢模式)

一、字串比較相等

  • “==” 比較地址是否相等
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 自動回收掉)。

2.同一個字串可能會被儲存多次, 比較浪費空間。

可以使用 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