JVM---对象
/**
* 【对象的实例化】
* <创建对象的方式>
* 1、new
* a, new XXX
* b, XXX.static方法
* c, XXXBuilder/ XXXFactory的方法
* 2、反射
* a, Class的newInstance
* ***空参构造器,权限必须是public
* b, Constructor的newInstance
* ***空参(或带参)构造器,权限不限制
* 3、clone
* ***不调用构造器
* 当前类需要实现Cloneable接口,实现clone()
* 4、反序列化
* 从网络、文件中获取 一个对象的二进制字节流
* 5、三方库Objenesis
* 动态生成对象
*
* <创建对象的步骤>
*
* Object object = new Object();
*
* 0: new #2 // class java/lang/Object
* 3: dup
* 4: invokespecial #1 // Method java/lang/Object."<init>":()V 对象成员变量显式初始化
* 7: astore_1
* 8: return
*
*
* 1,判断对象对应的类是否加载、链接、初始化
* 当 JVM遇到new指令,首先去检查new指令的参数 能否在方法区的常量池中找到该类的引用,并检查该类是否被加载、链接、初始化:
* 如果没有,在双亲委派的模式下,使用当前类加载器查找对应的class文件:
* 若没有找到文件,抛出ClassNotFoundException;
* 找到文件,进行类加载;
*
* 2,计算 对象所占堆内存大小,然后在堆中分配内存给新对象;
* 如果 对象成员变量 是引用类型,只需要分配引用变量空间即可,4字节;
* byte,short,int,char,boolean,float,引用类型 都是 4个字节;
* double,long是8个字节;
*
* 处理 内存分配 并发安全问题
* 1、使用CAS,保证操作的原子性
* 2、每个线程 预先 分配 一个 TLAB;
*
* 3,给 对象的实例属性 默认初始化;
*
* 4,设置 对象头
* 将对象的所属类、对象的hashcode、对象的GC信息、锁信息等 存储到对象头;
*
* 5,执行构造器<init>方法 进行 对象成员变量显式初始化(顺序执行):
* aa,成员变量 显式 初始化;
* bb,执行 实例代码块;
* cc,执行 类的构造器;
* dd,将 对象的地址 赋值给 引用变量
*
*
* <给对象属性赋值的操作>
* 1、属性的默认初始化
* 2、属性的显式初始化
* 属性显式赋值、代码块显式赋值、构造器显式赋值...
*
*
* <类的构造器<init>方法>
* public class User {
*
* private String name = "jack";
* private int age = 10;
*
* {
* name = "rose";
* }
*
* public User(){
* this.age = 11;
* }
*
* public User(String name){
* this.name = name;
* }
*
* public User(int age){
* this.age = age;
* }
* }
*
* 空参构造器<init>
* 0 aload_0
* 1 invokespecial #1 <java/lang/Object.<init>>
* 4 aload_0
* 5 ldc #2 <jack>
* 7 putfield #3 <com/an/object/User.name>
* 10 aload_0
* 11 bipush 10
* 13 putfield #4 <com/an/object/User.age>
* 16 aload_0
* 17 ldc #5 <rose>
* 19 putfield #3 <com/an/object/User.name>
* 22 aload_0
* 23 bipush 11
* 25 putfield #4 <com/an/object/User.age>
* 28 return
*
* String参数构造器<init>
* 0 aload_0
* 1 invokespecial #1 <java/lang/Object.<init>>
* 4 aload_0
* 5 ldc #2 <jack>
* 7 putfield #3 <com/an/object/User.name>
* 10 aload_0
* 11 bipush 10
* 13 putfield #4 <com/an/object/User.age>
* 16 aload_0
* 17 ldc #5 <rose>
* 19 putfield #3 <com/an/object/User.name>
* 22 aload_0
* 23 aload_1
* 24 putfield #3 <com/an/object/User.name>
* 27 return
*
* int参数构造器<init>
* 0 aload_0
* 1 invokespecial #1 <java/lang/Object.<init>>
* 4 aload_0
* 5 ldc #2 <jack>
* 7 putfield #3 <com/an/object/User.name>
* 10 aload_0
* 11 bipush 10
* 13 putfield #4 <com/an/object/User.age>
* 16 aload_0
* 17 ldc #5 <rose>
* 19 putfield #3 <com/an/object/User.name>
* 22 aload_0
* 23 iload_1
* 24 putfield #4 <com/an/object/User.age>
* 27 return
*/
/**
* 【对象的内存布局】
* <对象头(Object Header)>
* a,MarkWord(运行时元数据):
* hashCode、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳
* b,类型指针
* 指向 方法区中该对象所属的类型;
*
* ***如果是数组,还包括 数组长度;
*
* <实例数据(Instance Data)>
* 对象真正存储的有效信息
* 包括 程序自己定义的属性、从父类继承的属性
* ***规则:
* 对象中先放 父类属性,再放 子类属性;
*
* <对齐填充(padding)>
* 非必须,起到占位符的作用;
*
* eg:
* public class Account {}
*
* public class Customer {
*
* int id = 1001;
* String name;
* Account acc;
*
* {
* name = "匿名客户";
* }
*
* public Customer(){
* acc = new Account();
* }
* }
*
*
* Customer cust = new Customer();
*/

/**
* 【对象访问】
* JVM 如何 通过栈桢中的对象引用 访问到 对象实例的?
* 通过栈桢中 局部变量存储的引用类型的对象实例的具体内存地址;
*
* 访问方式:
* 直接指针(Hotspot采用)、句柄访问
*/
直接访问

句柄访问

浙公网安备 33010602011771号