java中的堆栈

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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来回收了:

技术分享

 

以上是关于java中的堆栈的主要内容,如果未能解决你的问题,请参考以下文章

关于JS堆栈与拷贝

JS中的堆栈内存

java中的引用数据数据类型是怎样的?

java---堆栈常量池的存储数据

Java中的堆栈方法区

Jvm(33),理解升级----有一点豁然开朗的的对堆栈方法区的理解