JAVA-初步认识-第七章-this关键字内存图解
Posted 照破山河万朵
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JAVA-初步认识-第七章-this关键字内存图解相关的知识,希望对你有一定的参考价值。
一.
对于静态的使用和注意事项已经讲解过了,接下来用一个例子,把静态所涉及的内存区域用图的形式给大家展现一下。
这里面进行了一个Person的描述,里面有两个成员变量name,age,同时有一个静态的变量country。接下来Person当中给我们提供了一个构造函数,能同时初始化性能和年龄。接下来还有一个非静态的方法show,可以显示出这个人的个人信息。接下来还有一个静态方法,它可以去显示我们国籍。
主函数中我们先用类名的形式调用了静态方法,紧接着创建了该类的对象,该类的对象调用了一个非静态的方法,这个方法只能被静态调用。
上面的例子中,主函数里面的语句Person p=new Person(); 这里显示括号里没有任何参数。在描述类中,没有空参数的构造函数,这里也就无法进行构造函数初始化。
以上面的描述为例,来将内存中的过程展现一下。(我觉着这里还是想将学到现在的所有面向对象知识点串起来,理清先后顺序。)
上面的截图内容挺不同寻常的,没有进行编译StaticDemo2的源程序,而是直接用java命令运行了StsticDemo2的类。就是说,没有编译就运行了?
这是在运行一个类,这个类就会被加载进内存,至于这个类被封装对象的过程,现在讲不了。这个部分到后面才能讲到。一加载进来就要进行空间的开辟。
无论怎样,计算机内存早就被划分为几个部分,来分别存储不同的东西。目前涉及的内存区域主要有三个,栈,堆,方法区。
区域划分完毕后,数据都在哪?是个问题。
方法存在哪?方法都存放在方法区里。解析一下,方法是如何在方法区存放的。
当StaticDemo2这个类被执行的时候,其实这个类就进内存了(程序运行都是在内存中操作的)。这个类一进内存,就开辟空间了。
在方法区划分了一片空间,存储StaticDemo2的类,分完以后,这个类里面有一个成员方法,就是StaticDemo2(),这个方法搞不清楚是哪来的?这个方法是这个类中的默认构造函数。会随着类一起加载进来。
主函数是静态的,main()会被加载入静态区,专门存储静态的数据。静态区里也会标明是StaticDemo2的类,然后里面有static main()的方法。
上面一左一右,左边是非静态区,右边是静态区。非静态区的方法和静态区的方法都是被共享的。为什么?以描述类中的show()方法而言,所有的对象都具备这功能,唯一的不同是什么?就是对象所封装的数据不一样。有的对象叫张三,有的对象就李四,但是大家都会说话,都会说的自己姓名和年龄,所以这个功能是共享的,这个功能就在方法区里面。只不过方法区分静态和非静态,因为调用方式和所属的不一样。非静态区域里面所有的成员都有一个this所属。为什么?非静态的内容只能被对象调用。而到了静态区,它有都有所属的类名。
在控制台上,将java StaticDemo2一回车,它就加载完了。加载完了,虚拟机就直接使用这个类名,调用方法。这个时候,main方法就进栈。main方法进栈以后,它就要运行里面内容,但是main方法里面的代码是存储在静态区。因为,源程序中的所有东西都被转换成了字节码文件存储起来了。mian本身就在静态区,它的代码也在静态区。
第一句Person.show()使用到了一个类,这个时候,这个类才加载。这个时候就去找,classpath路径下是否有Person.class文件。如果没有设置classpath,它就默认在当前目录下找,找到以后,就会把person.class文件加载进内存。一加载就会在方法区,分配空间了。Person类就进内存了,紧跟着Person的构造函数,以及show方法。它们加载完以后,static method的方法也会加载进来,这个方法所属Person类。这是我们所说的静态区,都是共享数据。紧接着,这里面还没完,里面还有country,country默认初始化为null,接着初始化为"CN",
加载完以后,是Person.method(),是类名在调用。用类名调用,只能找静态区。到静态区一找,在Person这个类所属的静态区当中或者说在静态区当中有Person类,Person类区域当中,有没有main方法呢?有的话,method的方法就进栈了。这个方法持有this么?没有,只有非静态区的才有this。到目前为止,堆里面没有东西。注意,method的方法从方法区里的静态区,到了栈内存中。下面的右截图的虚线是代码存放区,有的也叫做方法表。栈中的method是运行区,里面会有局部变量,运行完释放。栈区中存放方法的局部变量,System.out.println是不进来的,
方法进栈完以后,它就开始运行,运行的时候,就开始执行方法行动代码。有变量就开辟空间,没变量空间开辟完以后就会释放。一运行,Person.country就输出了,它在调用country这个一个变量。发现这个变量是类名.,如果不写类名.的话,class文件里也有。调用的时候,是找person里静态变量,一找到,就把CN给输出了。输出完以后,再往下就是return;method方法就弹栈了,到这呢,这个方法区就加载完毕了。
接着就执行第二句,Person p=new Person("java", 20); 接着主函数里面就多了个p,=右边是一个Person。堆内存中就开辟空间,分配地址编号,加载成员变量,默认初始化值。当然在类的描述当中,它可以描述描述自己的name和age,但是存在类型被使用,必须存到对象当中,因为这个name和age值是只能在对象中存在的。默认初始化完毕后,要接着构造函数初始化。这时,就要回头找,相对应的构造函数。这个时候,构造函数就进栈了,而这个构造函数在访问对象中的数据,它在给对象中的数据进行初始化。给哪个对象初始化呢?它不知道,所以它里面就持有一个this,而这时正好是0x0056的对象在调用构造函数,所以this等于0x0056. 紧跟着它的name就被赋值为”java“,age就被赋值为”20“,。紧跟着,这个函数完事以后,开始执行,构造函数里面的代码,this.name=name, this.age=age,一致性时,发现构造函数里面的name赋值给this.name,而this是0x0056的对象,也就是name=”java“赋值给了对象中的name。
这时候,构造函数就完毕了,它就要弹栈了。紧跟着,右边堆中的对象初始化就结束了。接着就把地址编号0x0056赋值给左边p,这样一来,p就指向了对象。
最后,执行p.show(),调用show方法。在方法区的非静态区有show方法。注意:在p.show在编译的时候,它会检查的源文件是否有show,没有的话,就编译失败了。可是运行的时候,它也会检查,发现有show,就让show进栈。show是非静态的,show得有this所属0x0056,执行里面代码,发现没有局部变量,只有输出语句。就直接执行输出语句。在输出的时候,发现输出country,大家都知道在counrty在编译完以后,在生成class文件,就已经有类名所属,所以它就找静态区里面的内容。找完以后,就打印了CN。接着找寻name和age的值,name和age前面有this,打印的都是0x0056的值,指向对象中的name和age值。找到以后,就输出了,CN,java,20.输出完以后,show方法就弹栈。
它弹栈以后,主函数的最后一句话就是return,这是默认,隐式,写不写都可以,系统会自动帮你加上,函数要结束。构造函数有return语句,一般方法有return语句。只有void的情况,return才可以省略。主函数有renturn,也弹栈。接着没有代码了,虚拟机结束了。这里面涉及线程。
以上是关于JAVA-初步认识-第七章-this关键字内存图解的主要内容,如果未能解决你的问题,请参考以下文章