簡(jiǎn)單談?wù)凧ava中的棧和堆
人們常說(shuō)堆棧堆棧,堆和棧是內(nèi)存中兩處不一樣的地方,什么樣的數(shù)據(jù)存在棧,又是什么樣的數(shù)據(jù)存在堆中?
這里淺談Java中的棧和堆
首先,將結(jié)論寫(xiě)在前面,后面再用例子加以驗(yàn)證。
Java的棧中存儲(chǔ)以下類(lèi)型數(shù)據(jù),棧對(duì)應(yīng)的英文單詞是Stack
基本類(lèi)型
引用類(lèi)型變量
方法

棧的優(yōu)勢(shì)是,存取速度比堆要快,僅次于寄存器,棧數(shù)據(jù)可以共享。但缺點(diǎn)是,存在棧中的數(shù)據(jù)大小與生存期必須是確定的,缺乏靈活性。
棧中主要存放一些基本類(lèi)型的變量(int, short, long, byte, float, double, boolean, char)和對(duì)象句柄。
棧有一個(gè)很重要的特殊性,就是存在棧中的數(shù)據(jù)可以共享。
Java的堆中存儲(chǔ)以下類(lèi)型數(shù)據(jù),堆對(duì)應(yīng)的英文單詞是Heap
實(shí)例對(duì)象

在函數(shù)中定義的一些基本類(lèi)型的變量(8種)和對(duì)象的引用變量都是在函數(shù)的棧Stack內(nèi)存中分配。當(dāng)在一段代碼塊中定義一個(gè)變量時(shí),java就在棧中為這個(gè)變量分配內(nèi)存空間,當(dāng)超過(guò)變量的作用域后,java會(huì)自動(dòng)釋放掉為該變量分配的內(nèi)存空間,該內(nèi)存空間可以立刻被另作他用。
堆Heap內(nèi)存用于存放由new創(chuàng)建的對(duì)象和數(shù)組。在堆中分配的內(nèi)存,由java虛擬機(jī)自動(dòng)垃圾回收器來(lái)管理。在堆中產(chǎn)生了一個(gè)數(shù)組或者對(duì)象后,還可以在棧中定義一個(gè)特殊的變量,這個(gè)變量的取值等于數(shù)組或者對(duì)象在堆內(nèi)存中的首地址,在棧中的這個(gè)特殊的變量就變成了數(shù)組或者對(duì)象的引用變量,以后就可以在程序中使用棧內(nèi)存中的引用變量來(lái)訪問(wèn)堆中的數(shù)組或者對(duì)象,引用變量相當(dāng)于為數(shù)組或者對(duì)象起的一個(gè)別名,或者代號(hào)。
引用變量是普通變量,定義時(shí)在棧中分配內(nèi)存,引用變量在程序運(yùn)行到作用域外釋放。而數(shù)組&對(duì)象本身在堆中分配,即使程序運(yùn)行到使用new產(chǎn)生數(shù)組和對(duì)象的語(yǔ)句所在地代碼塊之外,數(shù)組和對(duì)象本身占用的堆內(nèi)存也不會(huì)被釋放,數(shù)組和對(duì)象在沒(méi)有引用變量指向它的時(shí)候,才變成垃圾,不能再被使用,但是仍然占著內(nèi)存,在隨后的一個(gè)不確定的時(shí)間被垃圾回收器釋放掉。這個(gè)也是java比較占內(nèi)存的主要原因,實(shí)際上,棧中的變量指向堆內(nèi)存中的變量,這就是 Java 中的指針!
class Person {
int age;
}
public class LearnHeap {
public static void main(String args[]){
int a=10;
Person person = new Person();
person.age =20;
change(a,person);
System.out.println("a="+ a+",and person.age = "+person.age);
}
static void change(int a1, Person person){
a1 = 11;
person.age= 21;
System.out.println("a1="+ a1+",and age1 = "+person);
}
}
兩次的輸出結(jié)果是什么?猜測(cè)下。

以上程序內(nèi)存加載的執(zhí)行步驟:
第1步 —— main()函數(shù)是程序入口,JVM先執(zhí)行,首先將main方法壓入棧中,在棧內(nèi)存中開(kāi)辟一個(gè)空間,存放int類(lèi)型變量a,同時(shí)附值10。
在堆中分配一片區(qū)域,用來(lái)存放和創(chuàng)建Person對(duì)象,這片內(nèi)存區(qū)域會(huì)有屬于自己的內(nèi)存地址,假設(shè)是1001,然后給成員變量賦值,age=20
執(zhí)行結(jié)束后,構(gòu)造防范弾棧,Person創(chuàng)建完成,將Person的內(nèi)存地址1001賦值給person(此處person小寫(xiě),是引用變量類(lèi)型)
第2步 —— JVM執(zhí)行change()函數(shù),在棧內(nèi)存中又開(kāi)辟一個(gè)新的空間,存放int類(lèi)型變量a和對(duì)象Person中person
此時(shí)main空間與change空間并存,同時(shí)運(yùn)行,互不影響。
第3步 —— change()方法執(zhí)行,將a賦值為11,person對(duì)象的堆中年齡age賦值為21
第4步 —— change()執(zhí)行完畢,變量a立即釋放,空間消失。但是main()函數(shù)空間仍存在,main中的變量a仍然存在,不受影響。而person在堆中對(duì)應(yīng)的地址,所指的age已經(jīng)賦值=21
實(shí)際輸出如下:

結(jié)論:
如果a()方法中的基本類(lèi)型(8個(gè))變量x傳入b()方法中,并在b()中進(jìn)行了修改,則a()方法中的x的值保持不變
如果a()方法中的引用類(lèi)型 變量x傳入b()方法中,并在b()中進(jìn)行了修改,則a()方法中的x的值與b()保持一致

下面對(duì)8中基本類(lèi)型進(jìn)行簡(jiǎn)單的測(cè)試
package heapandStack;
public class LearnHeap02 {
public static void main(String args[]){
byte b=10;
short s=20;
int i=30;
long l =40l;
float f =12.34f;
double d = 100.123d;
char c = 'A';
boolean flag = true;
change(b,s,i,l,f,d,c,flag);
System.out.println(b);
System.out.println(s);
System.out.println(i);
System.out.println(l);
System.out.println(f);
System.out.println(d);
System.out.println(c);
System.out.println(flag);
}
static void change(byte a, short b, int c,long d, float f, double g, char h,boolean x){
a =11;
b=21;
c =31;
d =41l;
f=12.99f;
g= 200.123d;
h ='V';
x =false;
System.out.println(a);
System.out.println(b);
System.out.println(c);
System.out.println(d);
System.out.println(f);
System.out.println(g);
System.out.println(h);
System.out.println(x);
}
}
下面測(cè)試一下數(shù)組,是不是屬于實(shí)例對(duì)象類(lèi)型
public class LearnHeap03 {
public static void main(String args[]){
int a[] ={1,2,3};
change(a);
for(int i:a)
System.out.print(i+" ");
}
static void change(int[] a){
a[0]=4;
a[1]=5;
for(int i:a)
System.out.print(i+" ");
System.out.println("============ ");
}
}
從結(jié)果看出,數(shù)組的值被改變了

Java種8種基本數(shù)據(jù)類(lèi)型,并不包含String,String的值會(huì)被change函數(shù)改變嗎?String應(yīng)該存在棧中,還是堆中呢?
先直接上測(cè)試代碼
public class Learn04 {
public static void main(String args[]){
String s1 = new String("abcd");
String s2 = "asdfghjkl";
System.out.println(s1+", "+s2);
change(s1,s2);
System.out.println(s1+", "+s2);
}
static void change(String s1,String s2){
s1 ="123456";
s2 ="000000";
System.out.println(s1+", "+s2);
}
}
兩種的形式來(lái)創(chuàng)建String,第一種是用new()來(lái)新建對(duì)象的,它會(huì)在存放于堆中。每調(diào)用一次就會(huì)創(chuàng)建一個(gè)新的對(duì)象。 而第二種是先在棧中創(chuàng)建一個(gè)對(duì)String類(lèi)的對(duì)象引用變量s2,然后查找棧中有沒(méi)有存放"asdfghjkl",如果沒(méi)有,則將"asdfghjkl"存放進(jìn)棧,并令str指 向”abc”,如果已經(jīng)有”asdfghjkl” 則直接令s2指向“asdfghjkl”?!?/p>

既然講到兩種形式創(chuàng)建String,下面講一個(gè)String兩種形式創(chuàng)建的區(qū)別,先看一段代碼
public class Learn05 {
public static void main(String args[]){
String s1 = new String("abcd");
String s2 = "abcd";
boolean a =s1.equals(s2);
boolean b =(s1==s2);
System.out.println(a);
System.out.println(b);
String s3 = "abcd";
boolean a1 =s3.equals(s2);
boolean b1 =(s3==s2);
System.out.println(a1);
System.out.println(b1);
}
}

總結(jié)
到此這篇關(guān)于Java中的棧和堆的文章就介紹到這了,更多相關(guān)Java中棧和堆內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
淺談Spring如何解決循環(huán)依賴(lài)的問(wèn)題
這篇文章主要介紹了淺談Spring如何解決循環(huán)依賴(lài)的問(wèn)題,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09
java多線(xiàn)程應(yīng)用實(shí)現(xiàn)方法
以前沒(méi)有寫(xiě)筆記的習(xí)慣,現(xiàn)在慢慢的發(fā)現(xiàn)及時(shí)總結(jié)是多么的重要了,呵呵。雖然才大二,但是也快要畢業(yè)了,要加油2012-11-11
Java中的break和continue關(guān)鍵字的使用方法總結(jié)
下面小編就為大家?guī)?lái)一篇Java中的break和continue關(guān)鍵字的使用方法總結(jié)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-11-11
springboot @Valid注解對(duì)嵌套類(lèi)型的校驗(yàn)功能
這篇文章主要介紹了springboot~@Valid注解對(duì)嵌套類(lèi)型的校驗(yàn),主要介紹 @Valid在項(xiàng)目中的使用,需要的朋友可以參考下2018-05-05
SpringBoot 統(tǒng)一公共返回類(lèi)的實(shí)現(xiàn)
本文主要介紹了SpringBoot 統(tǒng)一公共返回類(lèi)的實(shí)現(xiàn),配置后臺(tái)的統(tǒng)一公共返回類(lèi),這樣做目的是為了統(tǒng)一返回信息,文中示例代碼介紹的很詳細(xì),感興趣的可以了解一下2022-01-01

