案例
Person.java
public class Person {
public String name;
public char sex;
public int age;
public void show(){
int age = this.age + 20;
System.out.printf("二十年后 姓名: %s 性别: %c 年龄: %d",name,sex,age);
}
}
PersonTest.java
public class PersonTest {
public static void main(String[] args) {
Person p = new Person();
p.name = "张三";
p.sex = '男';
p.age = 24;
p.show();
}
}
执行顺序
-
执行
java PersonTest
命令后,jvm将PersonTest.class
、Person.class
、System.class
三个文件加载到方法区。 -
jvm在加载的文件中找到main方法并将方法压栈到栈区。
-
接着main方法中声明了Person类型的引用p。
使用
new
关键字实例化Person对象存储在堆区,并将对象内存地址存储在p的内存中。 -
由于java中没有指针这个概念,堆区中的内容必须通过引用去访问。
-
接下来使用p的引用去访问堆区中对应对象的成员变量并改变它们的值。
-
通过对象引用p调用了成员方法show,此时show方法的内部变量被压栈,
开辟int类型大小的内存空间存储由cpu计算的成员变量age和字面量20的和。
-
show方法中对于System的调用同理,不再赘述。使用printf方法格式化输出相关变量的值。
-
完成show方法后,方法弹栈,销毁变量、清理内存空间。然回到main方法中。
-
main方法执行完毕,弹栈退出程序。
注意
- JVM中有方法区、堆区、栈区三个内存空间的划分。
- 方法区存储引用类型的代码,包括类中的静态变量。
- 堆区存放new出来的实例对象,也是GC自动垃圾回收机制的主要工作地方。
- 栈区中存放局部变量和方法的调用。每个方法调用会有一个独立的栈帧,方法退出后会清理掉。
- 方法区和堆区永远只有一个,栈区是每个线程有一个。