java调用new关键词去创建一个新的对象时,主要经历了什么?
1、确认类元信息是否存在。当虚拟机接收到 new 指令时,首先在 metaspace 内检查需要创建的类元信息是否存在。 若不存在则使用 ClassLoader + 包名+类名为 Key 进行查找对应的 class 文件。 如果没有找到文件,则抛出 ClassNotFoundException 异常 , 如果找到,则进行类加载(加载 - 验证 - 准备 - 解析 - 初始化),并生成对应的 Class 类对象。
2、分配对象内存。 首先计算对象占用空间大小,如果实例成员变量是引用变量,仅分配引用变量空间即可,即 4 个字节大小,接着在堆中划分—块内存给新对象。
3、设定默认值。 成员变量值都需要设定为默认值, 即各种不同形式的零值。
4、设置对象头。设置新对象的哈希码、 GC 信息、锁信息、对象所属的类元信息等。
5、执行 init 方法。 初始化成员变量,执行实例化代码块,调用类的构造方法,并把堆内对象的首地址赋值给引用变量。
ClassLoader类加载器
为了保证加载出来的类的唯一性(一个类只能被一种ClassLoader加载)及ClassLoader的扩展性(自定义加载),ClassLoader采用了双亲委派模式
ClassLoader主要有BootstrapClassLoader,ExtClassLoader、AppClassLoader,AppClassLoader的parent是ExtClassLoader,当parent加载不了的话会去使用BootstrapClassLoader加载,其主要区分如下:
BootstrapClassLoader:由C++编写,最顶层的加载类,主要加载核心类库,%JRE_HOME%\lib下的rt.jar、resources.jar、charsets.jar和class等。另外需要注意的是可以通过启动jvm时指定-Xbootclasspath和路径来改变Bootstrap ClassLoader的加载目录。比如java -Xbootclasspath/a:path被指定的文件追加到默认的bootstrap路径中。我们可以打开我的电脑,在上面的目录下查看,看看这些jar包是不是存在于这个目录。
ExtClassLoader:由java编写,扩展的类加载器,加载目录%JRE_HOME%\lib\ext目录下的jar包和class文件。还可以加载-D java.ext.dirs选项指定的目录。
AppClassLoader:由java编写,加载当前应用的classpath的所有类。