在Java代碼中,經常會使用到這樣的類的聲明實例化:java
Person per = new Person();數組
//這實際上是包含了兩個步驟,聲明和實例化函數
Person per = null; //聲明一個名爲Person類的對象perspa
per = new Person(); // 實例化這個per對象3d
聲明 指的是建立類的對象的過程;code
實例化 指的是用關鍵詞new來開闢內存空間。對象
它們在內存中的劃分是這樣的:blog
那什麼是棧內存(heap)和棧內存(heap)呢?內存
在函數中定義的一些基本類型的變量和對象的引用變量都在函數的棧內存中分配。棧內存主要存放的是基本類型類型的數據 如( int, short, long, byte, float, double, boolean, char) 和對象句柄。注意:並無String基本類型、在棧內存的數據的大小及生存週期是必須肯定的、其優勢是寄存速度快、棧數據能夠共享、缺點是數據固定、不夠靈活。ci
1
2
3
4
5
6
7
8
9
10
11
|
String str1 =
"myString"
;
String str2 =
"myString"
;
System.out.println(str1 ==str2 );
//注意:這裏使用的是str1 ==str2,而不是str1.equals(str2)的方式。
//由於根據JDK的說明,==號只有在兩個引用都指向了同一個對象時才返回真值
//而str1.equals(str2),只是比較兩個字符串是否相等
|
結果爲True,這就說明了str1和str2其實指向的是同一個值。
上述代碼的原理是,首先在棧中建立一個變量爲str1的引用,而後查找棧中是否有myString這個值,若是沒找到,就將myString存放進來,而後將str1指向myString。接着處理String str2 = "myString";;在建立完str2 的引用變量後,由於在棧中已經有myString這個值,便將str2 直接指向myString。這樣,就出現了str1與str2 同時指向myString。
特別注意的是,這種字面值的引用與類對象的引用不一樣。假定兩個類對象的引用同時指向一個對象,若是一個對象引用變量修改了這個對象的內部狀態,那麼另外一個對象引用變量也即刻反映出這個變化。相反,經過字面值的引用來修改其值,不會致使另外一個指向此字面值的引用的值也跟着改變的狀況。如上例,咱們定義完str1與str2 的值後,再令str1=yourString;那麼,str2不會等於yourString,仍是等於myString。在編譯器內部,遇到str1=yourString;時,它就會從新搜索棧中是否有yourString的字面值,若是沒有,從新開闢地址存放yourString的值;若是已經有了,則直接將str1指向這個地址。所以str1值的改變不會影響到str2的值。
堆內存用來存放全部new 建立的對象和 數組的數據
1
2
3
4
5
6
7
8
9
10
11
|
String str1 =
new
String (
"myString"
);
String str2 =
"myString"
;
System.out.println(str1 ==str2 );
//False
String str1 =
new
String (
"myString"
);
String str2 =
new
String (
"myString"
);
System.out.println(a==b);
//False
|
建立了兩個引用,建立了兩個對象。兩個引用分別指向不一樣的兩個對象。以上兩段代碼說明,只要是用new()來新建對象的,都會在堆中建立,並且其字符串是單獨存值的,即便與棧中的數據相同,也不會與棧中的數據共享。