[源碼]String StringBuffer StringBudlider(1String部分),stringbuffer源碼
String
/** The value is used for character storage. */
private final char value[];
/** The offset is the first index of the storage that is used. */
private final int offset; //第一個元素
/** The count is the number of characters in the String. */
private final int count;
/** Cache the hash code for the string */
private int hash; // Default to 0 哈希碼
/** use serialVersionUID from JDK 1.0.2 for interoperability */
private static final long serialVersionUID = -6849794470754667710L;
這裡有一個問題:為什麼final的東西沒有直接初始化但編譯不報錯?
只要在 對象 初始化OK之前給它賦值就行 。
你可以在 顯示初始化—隱式初始化-初始化塊初始化-構造器
任何一個地方給它初始化,編譯就不會報錯
說到String就不得不說一個事,叫做內存圖解
內存管理
Java內存分配與管理是Java的核心技術之一,之前我們曾介紹過Java的內存管理與內存洩露以及Java垃圾回收方面的知識,今天我們再次深入Java核心,詳細介紹一下Java在內存分配方面的知識。一般Java在內存分配時會涉及到以下區域:
◆寄存器:我們在程序中無法控制
◆棧:存放基本類型的數據和對象的引用,但對象本身不存放在棧中,而是存放在堆中(new 出來的對象)
◆堆:存放用new產生的數據
◆靜態域:存放在對象中用static定義的靜態成員
◆常量池:存放常量
◆非RAM存儲:硬盤等永久存儲空間
首先是 學基礎的程序員們最常提到的三塊地兒: 棧內存 堆內存 方法區
Stack棧內存
計算機中用來存放 非靜態變量 的區域, Stack負責 你在創建非靜態變量時,讓 這個東西進棧 ,當 這個變量出了作用域 , Stack 再讓它出棧。
靜態變量 是保存在 方法區靜態區域的。
Heap 堆內存
堆內存 裡邊可以開辟空間 分配對象,對象的首地址 賦值給 引用變量,這個就是Java裡邊的指針,這幾乎是唯一一塊受GC管理的地兒!
方法區
方法區裡邊 不僅放著方法而且放著靜態變量。裡邊有這麼幾塊區域比較重要:
方法區靜態區域 方法區非靜態區域 常量池
方法區靜態/非靜態區域 存的是什麼大家可以看我的另一篇博文:
//網址
常量池的話自然存的是常量
比如說 int a= 10; //編譯器就會去常量池找 有沒有10,如果之前用過就直接拿來,如果沒用過就 在常量池創建 10這個東西
但是 要注意的是 String的對象 也可以是常量:
String st=”123”; //這個就是String最特殊的地方
大家注意一下 String就這麼兩種表達方式:
這個地方最容易出的問題就是 == equals 的問題
== 與 equals方法 的區別
== 比較的是地址值
equals比較的也是地址值(更確切的說是hashCode),但是String裡邊重寫了這個方法,比較的是具體內容的值
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = count;
if (n == anotherString.count) {
char v1[] = char v2[] = anotherString. int i = offset;
int j = anotherString.offset;
while (n-- != 0) { //直接比較的是每個字符
if (v1[i++] != v2[j++])
return false;
}
return true;
}
}
return false;
}
字符串拼接
學這塊內容 大家務必搞清楚每一步 這些變量 常量 對象 在內存上的變化
String s1 = "hello";
String s2 = "world";
String s3 = "helloworld";
System.out.println(s3 == s1 + s2); //false,s1+s2是一個新的String的地址的引用
s3.equals((s1 + s2));
System.out.println(s3 == "hello" + "world");//true,拼接起來的是常量池中找到的
s3.equals("hello" + "world");
現在大家只要知道
凡是有變量參加的字符串拼接 拼出來的東西 一定是 new 出來的對象
若都是字符串常量的拼接 則還是直接去常量池找的常量
//這個東西我留著專門寫個東西介紹什麼叫做 編譯期確定下來了
假如你這麼寫:
String a = "ab";
final String bb = "b"; /編譯時已經放入常量池
String b = "a" + bb;
System.out.println((a == b)); //result = true
方法返回
String a = "ab";
final String bb = getBB();
String b = "a" + bb;
System.out.println((a == b)); //result = false
private static String getBB() { return "b"; }
這兩個東西我放到編譯期確定下來了這篇文章給大家分析一下
2016-10-21 更新