title: Java面向对象内存分析 date: 2018-07-28 11:12:50 tags: JavaSE categories: - Java - JavaSE
一、Java虚拟机的内存区域
Java虚拟机的内存可以分为三个区域:栈stack、堆heap、方法区method area
具体如图所示:
1.栈Stack
栈的特点:
-
栈描述的是方法执行的内存模型,每个方法被调用都会创建一个栈帧(存储局部变量,操作数,方法入口等)
-
JVM为每个线程创建一个栈,用于存放该线程执行方法的信息(实际参数,局部变量等)
-
栈属于线程私有,不能实现线程间的共享!
-
栈的存储特性是 “先进后出,后进先出”
-
栈是由系统自动分配,速度快!栈是一个连续的内存空间
2.堆Heap
堆的特点:
-
堆用于存储创建好的对象和数组(数组也是对象)
-
JVM只有一个堆,被所有线程共享
-
堆是一个不连续的内存空间,分配灵活,速度慢
如图:
3.方法区
方法区的特点:
-
JVM只有一个方法区,被所有线程共享
-
方法区实际也是堆,只是用与存储类、常量相关的信息!
-
用来存放程序中永远是不变或唯一的内容。
(类信息【Class对象】、静态常量、字符串常量等)
二、程序执行的内存变化过程
2.1 一个对象的创建分为四部
-
分配对象空间,并将对象成员变量初始化为0或为空
-
执行属性值的显示初始化
-
执行构造方法
-
返回对象的地址给相关变量
2.2 程序执行过程
1.方法区加载类的信息
类的代码信息,静待方法,静态常量被加载到方法区之中
2.调用main方法(程序执行的入口)
在栈中开辟一个栈帧,调用main方法
初始stu=null
下一步执行构造方法
开辟第二个栈帧,调用构造器,开始执行该方法
构造器根据方法区里面的模板信息开始在堆区新建一个对象。方法结束后在堆区新建对象成功
3.构造器执行结束
构造器执行结束,对象属性为初始状态
构造器方法的栈帧回收删除
stu指向新生成的stu对象
4.main方法继续执行
继续执行mian方法,为stu的属性进行赋值等, 例如使得部分属性指向字符串常量,最终方法执行结束
代码如下:
package top.dlkkill.oo;
public class Student {
public String id;
public String name;
public Student() {
System.out.println("Create a Student");
}
public static void live() {
}
public void study() {
}
public static void main(String[] args) {
Student stu=new Student();
stu.name="abc";
stu.id="111";
}
}
三、多态内存分析
内存图如图所示:
这里要注意:
-
super指向的是父类
-
无论是哪里的this,指向的都是新构造出来的Cat对象,比如在Aniaml里面有一个方法test();
方法中通过this.voice()调用了voice方法,如果新构造的是一个Cat对象,那么这个调用的voice方法就是调用的Cat里面重写的voice方法,而不是Animal方法!(这一点比较重要,在Servlet中,我们继承一个Servlet,并重写doGet方法就可以实现我们想要的功能就是基于这个原理,例如父类中有service()方法,方法调用了doGet,我们重写了doGet方法,这里就会调用我们重写的方法)
代码如下:
package top.dlkkill.oo;
public class AnimalTest {
public static void testAnimalVoice(Animal c) {
c.voice();
if(c instanceof Cat) {
((Cat) c).catchMouse();
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Animal a=new Cat();
Cat a2=(Cat) a;
testAnimalVoice(a);
}
}
class Animal{
String str;
public void voice() {
System.out.println("普通动物叫声");
}
}
class Cat extends Animal{
public void voice() {
System.out.println("喵喵喵");
}
public void catchMouse() {
System.out.println("抓老鼠");
}
}
程序执行,首先便会代码信息,类的信息以及静态方法、常量等加载到方法区之中。