目录
1. 对象的实例化
1.new:最常见的方式(本质是构造器)
变形1 : Xxx的静态方法
变形2 : XxBuilder/XxoxFactory的静态方法
2.Class的newInstance():反射的方式,只能调用空参的构造器,权限必须是public
3.Constructor的newInstance(Xxx):反射的方式,位于java.lang.reflect.Constructor 可以调用空参、带参的构造器,权限没有要求
4.使用clone() :不调用任何构造器,当前类需要实现Cloneable接口,实现clone()
5.使用反序列化:从文件中、从网络中获取一个对象的二进制流
6.第三方库Objenesis
对象的创建方式
2. 对象的创建步骤
1,如果遇到方法区中的new 操作符,会首先检查这个指令的参数在方法区的常量池中是否已经包含该类的符号引用,并且检查这个符号引用代表的类是否已经被加载,解析,初始化。如果包含,这不需要再加载该对象,如果没有则在双亲委派模式下,使用当前类的类加载器以ClassLOader+包名+类名为key进行查找对应的.class文件,如果没有找到文件,则抛出classNotFoundException异常,如果找到则进行类加载,并生成对象的class类对象。
2,为对象分配内存。计算当前对象所占用空间的大小,接着在堆内存中划分一块内存给新的对象,如果实例成员变量是引用变量,仅分配引用变量的空间大小,即4个字节的大小
在进行内存分配时:
- 如果内存是规整的(标记整理),那么虚拟机采用指针碰撞法,来为对象分配内存。意思是所有使用的内存在一边,空闲的内存在一边,中间存放一个指针作为分界点的指示器,分配内存就仅仅是把指针向空闲的那边进行移动一段与对象大小相同的距离,如果垃圾手机器选择的是serial。pernew这种基于压缩的算法,虚拟机采用这样的分配策略,一般使用带有compact的过程的收集器时,使用指针碰撞
- 如果内存不规整(标记压缩),虚拟机需要维护一个空闲的内存类表,该表记录了那些内存是可用的,在分配的时候从列表中找到一块足够大的空间划分给实例对象,并更新列表上面的内容
3,处理并发安全问题
采用cas失败重试,区域加锁保证更新的原子性
给每个线程分配一块TLAB区域。使用-XX:+/-UseTLAB参数来设定,jdk8默认开启
4,初始化分配到的空间:所有的属性设置默认值,保证对象实例字段在不赋值时可以直接使用
5,设置对象头:将对象所属的类(即类的元数据信息)对象的hashcode和对象的gc信息。锁信息等数据存储在对象的对象头中,这个过程的具体设置方式取决与jvm的实现
6,执行init方法,给对象进行显示的初始化,将初始化赋值,代码快赋值,构造函数中赋值语句组合成为init方法
初始化成员变量,执行实例化代码快,调用类的构造方法,并把对内对象的首地址赋值给引用变量,
3.对象的内存布局
3.1对象头信息
3.2 new Customer的过程
4. 对象的访问定位
jvm是如何通过栈帧中的对象引用访问到堆内存中的对象实例的
对象访问的两种方式:
-
句柄访问,在对内存中有一个句柄池,该句柄池中有到对象实例数据的指针,和到对象类型数据的指针
-
直接指针