棧與堆是Java
在Ram
中存放數據的地方,由Java
自動管理,不能直接設置。
堆 heap##
是一個運行時數據區,類的對象從中分配空間。由垃圾回收器管理。
對象:
通過new、newarray、anewarray、multianewarray
等指令建立,不需程序代碼來顯式的釋放。
JDK 5.0
前,Integer i = 3;
表達式是不被允許的,因為類與字面值不能通用,除String
。
JDK 5.0
后,可以這么寫,編譯器在后臺進行Integer i = new Integer(3);
轉換。
優點#####
1、動態地分配內存大小;
2、生存期不必事先告訴編譯器。因為是在運行時動態分配內存,垃圾回收器會自動回收不再使用的數據。
缺點#####
由于在運行時動態分配內存,存取速度較慢。
棧 stack##
是一個先進后出的數據結構,存放基本類型的變量和對象的引用變量(類實例)。
基本類型(primitive types)
共8種:int, short, long, byte, float, double, boolean, char
(無string基本類型)。
自動變量
基本類型通過諸如int a = 3;
的形式來定義,稱為自動變量。
自動變量存的是字面值,非類的實例(不是類的引用,也沒有類存在)。a
是一個指向int
類型的引用,指向3
這個字面值。
字面值的數據,由于大小可知,生存期可知(固定定義在某個程序塊里面,程序塊退出則字面值消失),故存在棧中。
優點#####
1、存取速度比堆要快,僅次于寄存器;
2、數據可以共享。
缺點#####
存在棧中的數據大小與生存期必須是確定的,缺乏靈活性。
數據共享#####
int a = 3;
int b = 3;
編譯器先處理int a = 3;
1、在棧中創建一個變量為a
的引用;
2、查找棧中是否有3
這個值,若沒有,則將3
存進棧中,將a
指向3
。
接著處理int b = 3;
3、在棧中創建一個變量為b
的引用;
4、查找棧中是否有3
這個值,因棧中已有,則將b
直接指向3
。
5、此時,令a = 4;
編譯器會搜索棧中是否有4
值,若沒有,則將4
存進棧中,將a
指向4
;若有,直接將a
指向4
。
因此a
值的改變不會影響到b
值,由編譯器完成,有利于節省空間。
總結###
基本類型變量:只在棧內存占用內存,保存對應的值,
引用類型變量:在棧內存保存的是一個指向堆內存的地址,通過這個地址,可以找到實例在堆區對應的對象。在在棧內存和堆內存都占用內存。Class c= new Class();
定義變量(實例)c
,new Class()
創建Class
對象。實例在棧中,對象在堆中,操作實例是通過實例的指針間接操作對象。多個實例可以指向同一對象。棧和堆中的數據銷毀并非同步。方法結束,棧中的局部變量立即銷毀,但是堆中對象不一定銷毀。因為可能有其他變量也指向該對象,直到棧中沒有變量指向堆中的對象時,它才銷毀,而且還不是馬上銷毀,要等垃圾回收掃描時才會被銷毀。
==、equals##
==
比較的是值【變量(棧)內存中存放的對象的(堆)內存地址】
equals
1、非包裝類數據:等同于==
2、包裝類數據:比較兩個對象的值是否相同【堆內存中的內容】
==
比equal
運行速度快,因為"=="只是比較引用。
包裝類數據
如Integer、String、Double
等將相應的基本數據類型包裝起來的類。這些類數據存放在堆中
源碼#####
Object
類中的equals
方法和==
一樣,引用數據類型重寫了equals
方法。
//Object類中equals方法
public boolean equals(Object obj) {
return (this == obj);
}
//String類重寫的equals方法
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String) anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
String 類#####
String
類由final
修飾,不能被繼承,是不可變類。
對象創建完成后,正常情況下,對象的狀態不會因外界的改變而改變(對象的狀態指對象的屬性,包括屬性的類型及屬性值)。
String str = "abc";
System.out.println(str); // abc
str = "def";
System.out.println(str); // def
str
是存儲在棧內存中指向堆內存中的引用,即存儲的是對象在堆中的地址,而非對象本身。
此時堆內存中依然存在abc
、def
對象。對于abc
對象本身而言,對象的狀態沒有發生任何變化。
String
是一個特殊的包裝類數據。
//兩種創建方式
(1)String str = new String("abc");
(2)String str = "abc";
第一種:用new()
創建的對象存放在堆中。每調用一次便創建一個新的對象。
第二種:先在棧中創建String
類的對象引用變量str
,并在堆中創建對象abc
。
//示例
String str1 = new String ("abc");
String str2 = new String ("abc");
System.out.println(str1==str2); // false
System.out.println(str1.equals(str2)); //true
//str1、str2分別創建了一個abc對象
String str1 = "abc";
String str2 = "abc";
System.out.println(str1==str2); //true
System.out.println(str1.equals(str2)); //true
//abc對象只在創建str1時創建,創建str2時并未創建新的abc對象,但指向str1創建的abc
String str1 = new String("abc");
String str2 = "abc";
System.out.println(str1==str2); //false
System.out.println(str1.equals(str2)); //true
//str1、str2分別創建了一個abc對象