示例:
class Birthday
{
private int day;
private int month;
private int year;
public Birthday(int d, int m, int y)
{
day = d;
month = m;
year = y;
}
}
public class Test
{
public static void main(String args[])
{
int date = 22;
Test test = new Test();
test.change(date);
Birthday bd= new Birthday(30,08,2001);
}
public void change(int i)
{
int i = 123;
}
对于上面这段代码:
1. 栈中:
- 局部变量及其数据:date = 22, i = 123, d = 30, m = 08, y = 2001
- 对象的引用:test, bd
2. 堆中
- 成员变量及其数据:day = 30, month = 08, year = 2001
- 对象:new Test(), new Birthday()
3. 方法区中:
- 方法: main(), change()
附图
执行顺序:
- main方法开始执行:int date = 22;
date局部变量,基础类型,引用和值都存在栈中。 - Test test = new Test();
test为对象引用,存在栈中,对象(new Test())存在堆中。 - test.change(date);
i为局部变量,引用和值存在栈中。当方法change执行完成后,i就会从栈中消失。 - Birthday bd= new Birthday(30, 08, 2001);
bd为对象引用,存在栈中,对象(new Birthday())存在堆中,其中d,m,y为局部变量存储在栈中,且它们的类型为基础类型,因此它们的数据也存储在栈中。day,month,year为成员变量,它们存储在堆中(new Birthday()里面)。当Birthday构造方法执行完之后,d,m,y将从栈中消失。
5.main方法执行完之后,date变量,test,bd引用将从栈中消失,new Test(),new BirthDate()将等待垃圾回收。
总结:
1. 栈:
- 局部变量(方法中):8种基本变量及其值—boolean、byte、char、short、int、float、long、double (不包含String—引用类型变量, 它只将变量放入栈中,而将值放入常量池)
- 对象的引用: 如 A a = new A(); 中的 a, String s = “哈哈” 中的 s. [而new A() 则存放与堆中, 哈哈 则存放于常量池中]
注:
每个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程,栈中的数据随线程生灭,且线程间数据不共享.
2. 堆:
- 对象: 如上方的 new A()
- 数组: int [] date = {2019, 8, 22}; 中 {} 内的内容
- 成员变量及值: 在方法外的变量(包括引用类型—String)
附图(数组)
3. 方法区:
- 方法:方法的名称和修饰符
- 常量: 被final修饰的成员变量, 常数, 字符串常量
- 静态变量(类变量):被static修饰