方法执行内存分析
注:栈原理图
部分源码示例
//方法调用的时候,在参数传递的时候,实际上传递的是变量中保存的那个"值"传过去了。
public class MethodTest01{
public static void main (String [] args){
int a=10;
int b=20;
int retvalue = sumInt (a,b);
System.out.println ("retvalue= " + retvalue);
}
public static int sumInt (int i,int j){
int result = i + j;
int num = 3;
int retvalue = divide (result, num) ;
return retvalue;
}
public static int divide (int x , int y){
int z = x / y;
return z;
}
}
内存分析图

处在栈顶的元素具有活跃状态。
递归方法执行内存分析
要点
1、什么是递归?
方法自身调用自身。
2、递归是很耗费栈内存的,递归算法可以不用的时候尽量别用。I
3、程序运行的时候发生以下错误【不是异常,是错误Error】:java.lang.StackOverflowError
栈内存溢出错误,错误发生无法挽回,只有一个结果,就是JVM停止工作。
4、递归必须有结束条件,没有结束条件一定会发生栈内存溢出错误。
5、递归即使有了结束条件,即使结束条件是正确的,也可能会发生栈内存溢出错误,因为递归的太深了
示例
public class RecursionTest01{
public static void main(String[] args){
System.out.println( "main begin");
dosome();
System.out.println( "main over");
}
//以下的代码片段虽然只有一份,但是可以被重复的调用,并且只要调用doSome方法就会在栈内存中新分配一块所属的内存空间.
public static void dosome{
System.out.println("doSome begin");
dosome();//这行代码不结束, 下一行程序不能执行System.out.println("doSome over");
}
部分源码
public class RecursionTest03 {
public static void main(String[] args) {
//1~4的和
int n = 4;
int retvalue = sum(n);
System.out.println(retvalue);
}
public static int sum(int n) {
//4+3+2+1
if (n == 1) {
return 1;
}
return n + sum(n - 1);
}
}
内存图分析

递归原理图

对象的创建与使用-内存分析
要点
1、变量必须先声明,再赋值才能访问。
注意:对于成员变量来说,没有手动赋值时,系统默认赋值。
类型 默认值
-------------------------
byte 0
short 0
int 0
long 0L
float 0.0F
double 0.0
boolean false
char \u0000
引用数据类型 null
null是一个java关键字,全部小写,表示空。是引用类型的默认值。
2、通过一个类可以实例化N个对象
实例化对象的语法:new 类名()
new运算符的作用是创建对象,在JVM堆内存当中开辟新的内存空间
方法区内存:在类加载的时侯,class字节码代码片段被加载到该内存空间当中。
栈内存(局都变量):方法代码片段执行的时候,会给该方法分配内存空间,在栈内存中压栈。
堆内存:new的对象在堆内存中存储
3、对象与引用
new运算符在堆内存中开辟的内存空间称为对象。
引用是一个变量,只不过这个变量中保存了另一个java对象的内存地址。
java语言当中,程序员不能直接操作堆内存,只能通过引用去访问堆内存当中对象内部的实例变量。
java中没有指针,不像c语言。
4、访问实例变量的语法格式
读取数据:引用.变量名; 修改数据:引用.变量名=值
部分源码
public class Student{
// 属性(描述状态),在java程序中以“成员变量”的形式存在。
// 学号
// 一个对象一份。
int no; // 这种成员变量又被称为“实例变量”。
// 姓名
String name;
// 年龄
int age;
// 性别
boolean sex;
// 住址
String addr;
}
public class OOTest01 {
public static void main(String[] args) {
int i = 10;
Student s = new Student();
}
}
内存图

部分源码
public class OOTest01 {
public static void main(String[] args) {
int i = 10;
Student s = new Student();
s.no = 10;
s.name ="jack";
s.age = 20;
s.sex= true;
s.addr = "北京";
Student stu=new Student();
}
}
内存图

部分源码
public class OOTest02
{
public static void main (String[] args){
//u保存内存地址指向堆内存的User对象User u=new User();
u.name = "jack" ;
//"jack"是一个java对象,属于string对象
u.addr = new Address ();
}
}
public class User{
int no;
//String是一种引用数据类型:代表字符串
//name是一个实例变量,是一个引用
String name;
//Address是一种引用数据类型:代表家庭住址
// addr是一个实例变量,addr是一个引用
Address addr ;
}
public class Address {
//city是一个引用:保存内存地址的一个变量,该变量保存内存地址指向了堆内存当中的对象。
String city;
String street;
Stringzipcode;
}
内存图

部分源码
public class OOTest03{
public static void main (String[] args){
User u=new User();
u.addr = new Address();
Address a = new Address();
u.addr = a ;
System.out.println (u.addr.city); //null
a.city = "天津";
System.out.println (u.addr.city);//天津
}
}
内存图

总结

1. JVM ( Java虚拟机)主要包括三块内存空间,分别是:栈内存、堆内存、方法区内存。
2、堆内存和方法区内存各有1个。一个线程一个栈内存。
3、方法调用的时候,该方法所需要的内存空间在栈内存中分配,称为压栈。方法执行结束之后,该方法所属的内存空间释放,称为弹栈。
4、栈中主要存储的是方法体当中的局部变量。
5、方法的代码片段以及整个类的代码片段都被存储到方法区内存当中,在类加载的时候这些代码片段会载入。
6、在程序执行过程中使用new运算符创建的java对象,存储在堆内存当中。对象内部有实例变量,所以实例变量存储在堆内存当中。
7、变量分类:
局部变量【方法体中声明】
成员变量【方法体外声明】
实例变量【前边修饰符没有static]
静交变量【前边修饰符中有static]
8、静态变量存储在方法区内存当中。
9、三块内存当中变化最频繁的是栈内存,最先有数据的是方法区内存,垃圾回收器主要针对的是堆内存。
10、垃圾回收器【自动垃圾回收机制、GC机制】
当堆内存当中的java对象成为垃圾数据,即没有更多的引用指向它的时候,会被垃圾回收器回收。
回收对象无法被访问,因为访问对象只能通过引用的方式访问。
构造方法
要点
关于java类中的构造方法:
1、构造方法又被称为构造的数/构造器/constructor
2、构造方法语法结构:
[修饰符列表]构造方法名(形式参数列表){
构造方法体;
}
3、回顾普通方法的语法结构:
[修饰符列表]返回值类型方法名(形式参数列表){
方法体;
}
4、对于构造方法来说,没有返回值,"返回值类型"不需要指定,并且也不能写void,只要写上void,那么这个方法就成为普通方法了。
5、构造方法的方法名必须和类名保持一致。
6、构造方法的作用?
构造方法存在的意义是,通过构造方法的调用,可以创建对象。
7、构造方法应该怎么调用?
① 普通方法调用:方法修饰符中有static的时候:类名.方法名(实参列表)、方法修饰符列表中没有static的时候:引用.方法名(实参列表)
② new 构造方法名(实参列表)
8、构造方法调用执行之后,有返回值吗?
每一个构造方法实际上执行结束之后都有返回值,但是这个"return值;"这样的语句不需要写。
构造方法结束的时候java程序自动返回值。并且返回值类型是构造方法所在类的类型。
由于构造方法的返回值类型就是类本身,所以返回值类型不需要编写。
9、注释和取消注释:ctrI +/ ,多行注释:ctrl +shift +/
10、当一个类中没有定义任何构造方法的话,系统默认给该类提供一个无参数的构造方法,这个构造方法被称为缺省构造器
11、当一个类显示的将构造方法定义出来了,那么系较则不再默认为这个类提供缺省构造器。
建议开发中手动的为当前类提供无参数构造方法。因为无参数构造方法太常用了。
12、构造方法支持重载机制。在一个类当中编写多个构造方法,这多个构造方法显然已经构成方法重载机制。
构造方法的作用:
1、创建对象
2、给实例变量赋值
成员变量之实例变量,属于对象级别的变量,这种变量必须先有对象才能有实例变量。
实例变量没有手动赋值的时候,系统默认赋值,那么这个系统默认赋值是在什么时候完成的呢? 是在类加载的时候吗?
不是,因为类加载的时候只加载了代码片段,还没来得及创建对象。所以此时实例变量并没有初始化。
实际上,实例变量的内存空间是在构造方法执行过程当中完或开辟的。完成初始化的。
系统在默认赋值的时候,也是在构造方法执行过程当中完成的赋值。
实例变量默认值:
byte , short,int, 1ong: 0
float, double: 0.0
bolean: false
引用数据类型: null
get set函数和构造方法编译器都可以自动生成
代码示例
pub1ic class ConstructorTest01{
public static void main String[] args) {
//创建User对象
//调用User类的构造方法来完成对象的创建
//以下程序创建了4个对象,只要构造函数调用就会创建对象,并且一定是在"堆内存"中开辟内存空间。User u1 = new User();
User u2 = new User(10);
User u3 = new User("zhangsan");
User u4 = new User(10, " zhangsan");
}
public class User {
//无参数构造方法
public User(){
System.out.println("User's Default Constructor Invoke!");
}
//有参数的构造方法
public User(int i){
System.out.println("带有int类型参数的构造器");
}
//有参数的构造方法
public User(String nane){
System.out.println("带有string类型的构造器");
}
//有参数的构造方法
public User(int i ,String name){
System.out.println("带有int,string类型的构造器");
}
}
**********本笔记整理于动力节点JavaSE基础课程 **************