学习总结(2022.03.21-2022.03.30)
JVM内存

- JVM栈。方法执行时占用的内存空间,方法以栈帧形式存储,方法内的局部变量会直接存储在栈帧中,方法执行完毕后出栈销毁,局部变量也被销毁。
- 堆。存储对象。new关键字即是在堆上开辟空间给对象。当没有引用指向对象时,该对象会被垃圾回收器执行垃圾回收机制(GC)回收内存。
- 方法区。
- 本地方法栈。存储JVM的本地(native)方法。
- 程序计数器:记录当前执行的行数。
传参问题
java是值传递,指调用方法时,传入的是实参的拷贝而不是实参本身。
所以下列代码是不可能得出a的两倍的。
1 | |
但是对引用数据类型而言,因为声明的是引用的拷贝,所以内存地址也是会被拷贝的。对引用数据类型进行修改,本身的引用不会发生改变,但是引用和引用的拷贝所指向的对象发生了改变。
所以下列代码b的后面是会加上.zip的。
1 | |
因为此时b和b的拷贝指向了新的对象b+.zip。
看起来似乎是引用传递,但是下列代码是一个反例。
1 | |
交换两个拷贝的值,其实就是在交换它们指向的对象,而原先的引用不受影响。在方法结束后,两个拷贝被销毁,交换失败。
类加载
JVM认识一个我们创建的类,叫类加载。类加载在一次程序运行中只有一次,且类加载是懒加载的,一些场景会触发类加载,称为类加载的时机,有以下几种:
- 创建该类对象(new一个对象)
- 启动该类的main方法
- 访问某个类的静态成员(包括变量和方法)
- 子类类加载会触发父类类加载
static修饰的成员是随着类加载完毕就存在的,所以不需要创建对象就可以访问。
创建对象也不依赖于类加载。
类生命周期

类加载过程的三个步骤:加载,连接,初始化
加载主要是将class字节码读取进JVM
连接主要是将静态成员变量进行默认初始化,保证其永远最先进行。
初始化主要执行static相关的内容,包括为静态成员变量赋值,以及执行静态代码块。
成员变量的赋值方式和顺序
- 默认初始化
- 显式赋值
- 构造代码块
- 构造器赋值
其中默认初始化和构造器赋值永远是第一步和最后一步(掐头去尾)
创建对象过程中结构执行顺序(全)
- 类加载。首先程序要从有main方法的类中开始执行,所以要先对其进行类加载。(要考虑发生连环类加载的情况,首先有父类存在的话要先执行父类类加载,其次有静态成员变量或者静态代码块创建对象的话要先执行该对象的类加载)
- 执行静态成员变量的初始化。(包括显式赋值和静态代码块)
- 创建对象。首先找到对象的构造器,如果有显式调用其他构造器,则跳转至该构造器的类,执行构造代码块和显式赋值,最后执行该构造器。如果没有,则是跳转至父类的无参构造器(无父类则是跳转至Object,但是不影响),执行父类的构造代码块和显式赋值。