画图分析类实例化及操作时在内存中的变化及表现形式

  1. package com.test;
  2. public class Main {
  3. public static void main(String[] args) {
  4. //实例化一个Cat对象
  5. Cat cat = new Cat();
  6. //给成员变量赋值
  7. cat.name = "招财";
  8. cat.age = 2;
  9. cat.weight = 2.02;
  10. //打印
  11. System.out.println("小猫的名字:"+cat.name + " 小猫的年龄:"+cat.age);
  12. //调用成员方法
  13. cat.say();
  14. }
  15. }
  16. class Cat {
  17. /**
  18. * 成员变量 name
  19. */
  20. String name;
  21. /**
  22. * 成员变量 age
  23. */
  24. int age;
  25. /**
  26. * 成员变量 weight
  27. */
  28. double weight;
  29. public void say()
  30. {
  31. System.out.println("喵喵~~");
  32. }
  33. }

上面这段代码首先有个主程序的类 Main,这个我们不过多说明。我们主要分析 main 函数体里面的这段代码。
我们需要知道在 Cat 类中,定义了三个成员属性:name、age、weight;定义了一个成员方法:say ();

在 main () 函数里实例化对象 cat, 内存中在堆区内会给实例化对象 cat 分配一个内存地址,然后我们给对象 cat 进行了赋值并且打印了一些信息,最后调用了成员方法 say () ,程序执行完毕。
1. 在程序的执行过程中,首先 Main 类中的成员属性和成员方法会加载到方法区
分析类实例化及操作时在内存中的变化及表现形式 - 图1
2. 程序执行类 Main 的 main () 方法时,main () 函数方法体会进入栈区,这一过程叫做进栈 (压栈)。
分析类实例化及操作时在内存中的变化及表现形式 - 图2
3. 程序执行到 Cat cat = new Cat(); 时,首先会把 Cat 类的成员属性和成员方法加载到方法区,此时方法的内存空间地址为 1x000000,同时在在堆内存开辟一块内存空间 74a14482,用于存放 Cat 实例对象,并给成员属性及成员方法分配对应的地址空间,比如下图的 0x000001~0x000004 即为对象分配的堆内存地址,但此时成员属性都是默认值,比如 int 类型默认值为 0,String 类型默认值为 null,成员方法地址值为方法区对应成员方法体的内存地址值;然后在栈内存中会给变量 cat 分配一个栈地址 34b23231,用来存放 Cat 实例对象的引用地址的值 74a14482。
分析类实例化及操作时在内存中的变化及表现形式 - 图3
4. 接下来对 cat 对象进行赋值
//给成员变量赋值 cat.name = “招财”; cat.age = 2; cat.weight = 2.02;
先在栈区找到引用变量 cat,然后根据地址值找到 new Cat () 对象的内存地址,并对里面的属性进行赋值操作。由于成员属性 name 的类型为 String,为引用数据类型,所以此时会在常量池开辟一块地址空间 2x00000000,存放招财这个值,而 age 的类型为 int,weight 的类型为 double,都为基本数据类型,所以值直接存放堆中。
分析类实例化及操作时在内存中的变化及表现形式 - 图4
5. 当程序执行到 cat.say() ; 方法时,会先到栈区找到 cat 这个引用变量(这个变量存的是对象的引用地址),然后根据该地址值在堆内存中找到 new Cat () 对象里面的 say() 方法进行调用,在调用 say() 方法时,会在栈区开辟一块空间进行运行。
分析类实例化及操作时在内存中的变化及表现形式 - 图5
6. 在方法体 void say() 被调用完成后,就会立刻马上从栈内弹出(出站 ),最后,在 main () 函数完成后,main () 函数也会出栈

参考文档

本文为 joshua317 原创文章,转载请注明:转载自 joshua317 博客 https://www.joshua317.com/article/189