缓冲池、String/StringBuffer/StringBuilder、intern()
1.緩沖池
1.1 new Integer(123) 與 Integer.valueOf(123) 的區別在于:
- new Integer(123) :每次都會新建一個對象
- Integer.valueOf(123) :會使用緩存池中的對象,多次調用會取得同一個對象的引用。
1.2?valueOf() 方法的實現
先判斷值是否在緩存池中,如果在的話就直接返回緩存池的內容。
public static Integer valueOf(int i) {if (i >= IntegerCache.low && i <= IntegerCache.high)return IntegerCache.cache[i + (-IntegerCache.low)];return new Integer(i); }1.3?在 Java 8 中,Integer 緩存池的大小默認為 -128~127。
1.4 自動裝箱
編譯器會在自動裝箱過程調用 valueOf() 方法,因此多個 Integer 實例使用自動裝箱來創建并且值相同,那么就會引用相同的對象。
Integer m = 123; Integer n = 123; System.out.println(m == n); // true1.5?基本類型對應的緩沖池如下:
- boolean values true and false
- all byte values
- short values between -128 and 127
- int values between -128 and 127
- char in the range \u0000 to \u007F
在使用這些基本類型對應的包裝類型時,就可以直接使用緩沖池中的對象。
2. String
2.1 概覽
String 被聲明為 final,因此它不可被繼承。
內部使用 char 數組存儲數據,該數組被聲明為 final,這意味著 value 數組初始化之后就不能再引用其它數組。
并且 String 內部沒有改變 value 數組的方法,因此可以保證 String 不可變。
public final class String implements java.io.Serializable, Comparable<String>, CharSequence {/** The value is used for character storage. */private final char value[];...2.2?不可變的好處
2.2.1 可以緩存 hash 值
因為 String 的 hash 值經常被使用,例如 String 用做 HashMap 的 key。
不可變的特性可以使得 hash 值也不可變,因此只需要進行一次計算。
2.2.2 String Pool 的需要
如果一個 String 對象已經被創建過了,那么就會從 String Pool 中取得引用。
只有String 是不可變的,才可能使用 String Pool。
2.2.3 安全性
String 經常作為參數,String 不可變性可以保證參數不可變。
例如在作為網絡連接參數的情況下如果 String 是可變的,那么在網絡連接過程中,String 被改變,改String 對象的那一方以為現在連接的是其它主機,而實際情況卻不一定是。
2.2.4 線程安全
String 不可變性天生具備線程安全,可以在多個線程中安全地使用。
3. String, StringBuffer and StringBuilder(詳細介紹)
3.1. 可變性
- String 不可變;
- StringBuffer 和 StringBuilder 可變。
3.2 線程安全
- String 不可變,因此是線程安全的;
- StringBuilder 不是線程安全的;
- StringBuffer 是線程安全的,內部使用 synchronized 進行同步。
3.3 String.intern()
使用 String.intern() 可以保證相同內容的字符串變量引用同一的內存對象。
下面示例中,s1 和 s2 采用 new String() 的方式新建了兩個不同對象,而 s3 是通過 s1.intern() 方法取得一個對象引用。intern() 首先把 s1 引用的對象放到 String Pool(字符串常量池) 中,然后返回這個對象引用。因此 s3 和 s1 引用的是同一個字符串常量池的對象。
String s1 = new String("aaa"); String s2 = new String("aaa"); System.out.println(s1 == s2); // false String s3 = s1.intern(); System.out.println(s1.intern() == s3); // true System.out.println(s1 == s3); // false如果是采用 "bbb" 這種使用雙引號的形式創建字符串實例,會自動地將新建的對象放入 String Pool 中。
String s4 = "bbb"; String s5 = "bbb"; System.out.println(s4 == s5); // true在 Java 7 之前,字符串常量池被放在運行時常量池中,它屬于永久代。
而在 Java7,字符串常量池被移到 Native Method 中。這是因為永久代的空間有限,在大量使用字符串的場景下會導致OutOfMemoryError 錯誤。
?
總結
以上是生活随笔為你收集整理的缓冲池、String/StringBuffer/StringBuilder、intern()的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Web 页面请求过程
- 下一篇: float 与 double、隐式类型转