java中的堆栈
数据存放在哪里?
栈中存放的数据:基本类型数据、对象引用的句柄(指向对象的地址)
堆中存放的数据:创建的对象
静态方法区存放的数据:字面量
例如:
String str = new String( "hello" );
上面的语句中变量str放在栈上,用new创建出来的字符串对象放在堆上,而"hello"这个字面量放在静态区。
数据类型的分类
基本类型
基本类型是比对象更小的单位,不是new出来的,有byte 、chart 、short 、int 、long 、float 、double 、boolean八种基本数据类型。变量直接包含了具体的值,存储在栈中。
引用类型
引用类型是指new出来的对象被放置在堆中,变量实际是指向一个对象的句柄。
堆栈的区别
1、栈是立即被访问的,而堆要跳几重寻址才能访问到,所以理论上栈的访问效率要比堆高,所以能用 int 就不要 new integer()
2、每个线程都有自己独立的栈,当方法执行完毕,栈里面的内存空间就会自动被回收,而堆在整个JVM中只有一个(所以堆中的数据可被多个线程共享),堆里面的内存空间由GC来负责回收。
3、静态方法也是全局只有一个实例,被所有线程共享。
引用类型变量赋值详解
demo1:
MyObject obj1; // Step1 obj1 = new MyObject( ); //Step2 obj1.setName( "wxh" ); //Step3 MyObject obj2 = obj1; //Step4 obj2 = new MyObject( "wxh2" ); //Step5
Step1 -- Step2 :obj1由null变成存储指向MyObject对象的地址,存储在栈中,MyObject存储在堆中
Step2 -- Step3 :MyObject的name属性变成"wxh"
Step3 -- Step4 :obj2也指向了MyObject对象,值跟obj1相同
Step4 -- Step5 : 堆中创建了另外一个MyObject对象,obj2指向了该对象,obj1没变
demo2:基本数据类型的参数传递
public class Test { public static void main(String[] args) { Test test = new Test( ); int number = 100; test.changeInt( number ); System.out.println( " 执行changeInt方法后:" + number ); } public void changeInt(int value) { value = 50; System.out.println( "在方法内部:" + value ); } }
运行结果:
在方法内部:50
执行changeInt方法后:100
其栈图如下:
demo3:引用数据类型的参数传递
public class Test2 { public static void main(String[] args) { Test2 test = new Test2( ); MyDate d = new MyDate( 1997, 7, 1 ); System.out.println( "执行方法前:" + d ); test.changeValue( d ); System.out.println( "执行方法后:" + d ); } public void changeValue(MyDate date) { date.setYear( 1999 ); date.setMonth( 12 ); date.setDay( 20 ); System.out.println( "在方法内部:" + date ); } }
运行结果:
执行方法前:1997-7-1
在方法内部:1999-12-20
执行方法后:1999-12-20
说明对象内属性的值被修改了
堆栈图说明如下:
首先,执行MyDate d = new MyDate(1997,7,1) 时:
之后调用changeValue方法,传date变量进来,date变量接收的是d引用的地址:
修改堆内存中的数据为1999-12-20 时:
changeValue方法执行完出栈,此时d还是指向原来堆里面的内存,只是这个内存里面的值被修改了:
demo4:
public class Test2 { public static void main(String[] args) { Test2 test = new Test2( ); MyDate d = new MyDate( 1997, 7, 1 ); System.out.println( "执行方法前:" + d ); test.changeValue( d ); System.out.println( "执行方法后:" + d ); } public void changeValue(MyDate date) { date = new MyDate( 1999, 12, 20 ); System.out.println( "在方法内部:" + date ); } }
运行结果:
执行方法前:1997-7-1
在方法内部:1999-12-20
执行方法后:1999-7-1
堆栈图说明如下:
执行MyDate d = new MyDate(1997,7,1) 时:
执行changeRef方法时:
changeRef方法执行:date = new Date(1992,12,20) :
changeRef方法执行后出栈,此时d仍然指向“1997-7-1”,而堆中的“1999-12-20”此时就没有了任何变量去引用,此时他就得等待GC来回收了: