高级内存
对象 与 对象变量
数据格
1 int a = 1;
变量 是 数据格
变量的值 是 数据格里的数据
对象变量
对象变量 是 数据格
对象变量的值 是 对象*
1 Player player = new Player(); ------ ------------- 对象变量 新建 一个 对象
空
用来代表没有对象
1 Player player = null;
有变量,变量里没有对象
空指针异常
如果对象变量里是 null
能通过编译,但是运行时 调用 .
运算符时 会报错
1 2 3! <4 public void run(){ Player player = null; System.out.println(player.getName()); NullPointerException}
值类型 与 引用类型 的 区别
是什么
编程的 两大 内存分配和管理规则
地址
任何变量 在开辟时都会有三样东西同时存在
变量 | 数据格 |
---|---|
值 | 值 |
地址 | 数据格的id |
赋值
在 Java 中,赋值永远会赋值变量格里的值
值类型
是什么
采用值类型的内存分配方式,变量里存储的是数据本身
图示
1 2 3 4 Point p1 = Point(3, 4);Point p2 = Point(5, 6);p1 = p2;p1.x = 7;



Java
Java 中的 对象没有采用这种内存管理机制
C++ 中的 struct 可以采用这种内存机制管理内存
Java 中的 8大基础类型采用了这种内存管理机制
Java 的 基础类型
1 2 3 4 int a = 3;int b = 4;a = b;a = 5



指针
是什么
一个变量里的存的值,正好是另外一个变量的地址
引用
在 java 里 叫 引用
引用类型
是什么
内存被分为 堆 和 栈 两大区域。
局部变量、参数 的 内存 开辟在 栈里。
对象属性 的 内存 开辟在 堆里。
采用引用类型的内存分配方式,对象变量里 存的 是 对象在 堆里的 地址
图示
1 2 3 4 Point p1 = new Point(3, 4);Point p2 = new Point(5, 6);p1 = p2;p1.x = 7;



. 运算符
会产生地址跳跃
理解
网红的故事
网红 是 对象,是 对象在堆里开辟的空间
网红的手机号 是 对象在堆里的地址
小纸条 是 对象变量,是 指针,存储着 网红的手机号
Java
Java 中的 对象类型(非基础类型),采用这种内存管理方式
对象 与 对象变量
对象变量里存的是对象的引用
对象变量赋值, 赋值的是对象变量里的内容
1 2 3 Point p1 = new Point(3, 4);Point p2 = new Point(5, 6);Point p3 = p2;
内存管理 与 代码执行 规则
基于下面的代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public class Cla { private int a = 1; public Cla(int a) { this.a = a; } public void func1(int value) { int a = 32; // 检查点 2 } public void func2() { // 检查点 4 System.out.println(a); func3(); } public void func3() { int b = 4; // 检查点 5 }}
1 2 3 4 5 6 7 8 9 10 11 12 13 public class Driver { public static void main(String[] args) { Cla obj1 = new Cla(1); Cla obj2 = new Cla(2); int value = 7; // 检查点 1 obj1.func1(2); // 检查点 3 obj2.func2(); // 检查点 6 }}
关于检查点
上面的代码的检查点 的序号 是按着执行时经过的顺序 编号的
变量开辟
规则
局部变量 / 参数 在 栈里
属性 在 堆里
案例
在 检查点 1 的时候
两个 Cla 对象开在 堆里
作为 main 函数的局部变量 obj1, obj2 和 value 开在栈里
此时的内存:

调用方法前的准备
规则
当调用方法时,需要先对引导的对象变量 和 参数 进行求值(缩合)
案例
Driver 中的 Line 8
obj1.func1(2);
引导的对象变量 obj1 必须先缩合,才能调用 func1
参数是 值 2,无需缩合,如果是变量,则需要缩合
变量缩合
规则
变量会缩合为里面的值
一般变量 就是 里面的值
对象变量 也是 里面的值,不过这个值 是另外一个 对象的地址
案例
Driver 中的 Line 8
obj1.func1(2);
obj1 变量会缩合为 201
201.func1(2);
调用方法
规则
Step 1
增加 隔板
每个函数都有自己的变量空间
调用函数,会为函数开辟新的内存区域,在栈里
Step 2
传输 this
为 被调用函数 创建一个 this 变量,在栈里
谁点函数,this 就是谁
Step 3
传输 参数
为 被调用函数 创建参数变量,在栈里
传参的值 会 过去
案例
在 检查点 2 的时候 其实 方法已经调用进去了
此时根据上面规则中的操作,增加了 this 和 value 的变量
除此之外,还因为 Cla 的 Line 9 增加了 局部变量 a
此时的内存:

方法销毁
规则
删除 所有变量
删除 隔板
传输 返回值
案例
在 检查点 3 的时候 func1 函数已经调用完毕
此时曾经创建的隔板,和隔板下的变量 全部被销毁
func1 没有返回值,所以不需要考虑返回值的事情
此时的内存:

this 补充 属性
规则
如果 在栈的隔板下方 找不到 变量,则补充 this
案例
在 检查点 4 的时候,func2 函数刚刚被调用完毕
此时的内存

接下来要执行 Line 14
System.out.println(a);
但 堆栈结构的 隔板下方 并没有 a。
所以代码会变为
System.out.println(this.a);
从而可以根据之前的变量缩合规则变为
System.out.println(202.a);
this 补充 方法
规则
如果调用方法前面,没有对象变量引导,则补充 this
案例
Cla 的 Line 16 时
func3();
func3 是 省略写法,前面缺少了对象变量引导,所以补 this
this.func3();
也就是
202.func3();
持续进入
规则
调用方法时,如果进入新的方法,则会持续增加隔板
案例
Cla 的 Line 16 会导致 func2 执行时进入 func3
在 检查点 5 时,内存为

逐级退出
规则
每个方法调用完了,都会销毁它自己的资源和隔板
案例
Driver 的 Line 10 曾经在调用 func2 时 导致 间接调用 func3
但在 检查点 6 时, func2 已经完成了调用, func2 内部的 func3 也必定结束了调用
此时,func3 和 func2 在栈中的空间 已经接连被销毁。
在 检查点 6 的内存:
