前言
如果没有面向对象基础,先看一个Java类看懂面向对象.
当new对象时,才会涉及到内存的分配,此时构造器构造对象的静态特征和动态行为。
JVM内存分为函数栈、堆、方法区。
一、内存分析
package com.xhu.java;
import java.util.Date;
import java.util.GregorianCalendar;
/**
* 一群学生抽象出来的学生类,抽象就是一个向上找描述物体的框架过程。
*/
public class Student {
/**
* 第一部分,一群物体抽象出来的静态特征,它们的公共特征。对一群物体观察得越仔细,抽象出来的静态特征越多。
*/
public String idCard;//每个学生都有身份证号码
public String name;//每个学生都有姓名
public Date birth;//每个学生都有出生时间
/**
* 第二部分,一群物体抽象出来的动态行为,它们的公共行为。对一群物体观察得越仔细,抽象出来的动态行为越多。
*/
public void eat() {//每个学生都有吃饭的行为。
//面向过程去编写吃饭这个行为。
System.out.println("洗手");
System.out.println("吃饭");
System.out.println("洗碗");
}
public void sleep() {//每个学生都有睡觉的行为。
//面向过程去编写睡觉这个行为。
System.out.println("洗漱");
System.out.println("上床");
System.out.println("睡觉");
}
/**
* 这是动态行为跟静态特征关联协作的地方。
*/
public void updateName(String name) {//每个学生可以修改他的名字
this.name = name;
}
/**
* 第三部分,构造器,向上的过程为抽象,向下的过程就是具体。比如来了一个新同学,一个真实的学生,此时就需要把他实例构造出来。
*/
public Student(String idCard, String name, Date birth) {//构造一个真实的对象,对他的基本特征设定一个具体的值
this.idCard = idCard;
this.name = name;
this.birth = birth;
}
/*public Student Student(){
return this;
}*/
/**
* 实例化对象,Java要求所有函数写入类之中,写一个该类的入口函数(该函数属于类,所以应该是static)main函数。(run一个类,必须要有入口函数main)
*/
public static void main(String[] args) {
//通过new构造器来向下构造一个具体的对象
Student s1 = new Student("111111111111","Jack马", new GregorianCalendar().getTime());
Student s2 = new Student("222222222222","Pony马",new GregorianCalendar().getTime());
}
}
1)进入主函数,开辟一个栈帧,有自己的变量
注:这里的参数有默认赋值,不同类型有不同的默认方式
所以此时args = null;s1 = null;s2 = null.
2)
Student s1 = new Student("111111111111","Jack马", new GregorianCalendar().getTime());
,此时要new出对象s1,调用构造函数,开辟栈帧,开辟对象空间并赋值。
3)执行
Student s2 = new Student("222222222222","Pony马",new GregorianCalendar().getTime());
,前一个构造函数结束,栈顶帧出栈,调用新的构造器开辟新的栈帧。
4)调用构造函数完毕,出栈。此时,买main函数也调用完毕,main函数出栈,程序结束。
总结
1)JVM的函数栈、堆、方法区。
2)面向对象时的简单内存分析。
参考文献
[1] 尚硅谷Java SE–高淇
附录
1、JVM内存模型介绍
1)对于每一个线程,都有
a)程序计数器,记录程序运行到那一步,当中断结束后,能从该地方继续执行。
b)虚拟机栈,也称函数执行栈,main函数打底,调一个函数就将开辟栈帧,即进栈;调用结束就出栈。栈帧里面存有局部变量表,编译时期可知基本数据类型、对象引用、方法出口。
c)本地方法栈,对于系统调用函数的函数栈。
注:这三个属于线程私有,不共享。
2)对于堆,创建的对象,直接分配在堆上。(只有一个堆)堆被所有的线程共享。为了便于快速垃圾回收,将堆划分为新生代和老年代。
3)对于方法区,本质也是堆,不连续存储,被所有线程共享。存储一些类信息、常量、静态变量、即时编译后的代码等数据(不变的信息)。
注:方法区是一种规范,而不同版本的JDK实现不同。
JDK7以前:方法区就是堆中的“永久代”。
JDK7,部分去“永久代”,把静态变量、字符串常量移到了堆内存中。
JDK8,“永久代”不存在了,类信息、编译后的代码信息和数据存到直接内存上,即本地内存上。不在堆内层上。
- 运行常量池,存字面量、如文本字符串、final常量;存符号引用,即与编译相关的常量。
- 直接内存,直接内存并不属于Java规范规定的属于Java虚拟机运行时数据区的一部分。Java 的NIO可以使用Native方法直接在java堆外分配内存,使用DirectByteBuffer对象作为这个堆外内存的引用。