沧州网站制作公司,wordpress 5.0火车头发布模块,怎么开小程序店铺,网站的360度全景图片怎么做文章目录 1、创建对像的几种方式1、new关键字2、反射3、clone4、反序列化 2、创建过程步骤 1、检查类是否已经被加载步骤 2、 为对象分配内存空间1、指针碰撞针对指针碰撞线程不安全#xff0c;有两种方案#xff1a; 2、空闲列表选择哪种分配方式 步骤3、将内存空间初始化为… 文章目录 1、创建对像的几种方式1、new关键字2、反射3、clone4、反序列化 2、创建过程步骤 1、检查类是否已经被加载步骤 2、 为对象分配内存空间1、指针碰撞针对指针碰撞线程不安全有两种方案 2、空闲列表选择哪种分配方式 步骤3、将内存空间初始化为零值步骤4、对对象进行必要的设置步骤5、执行实例的初始化方法init 总结注意 谈对象的创建过程的话先来介绍介绍创建对象的几种方式
1、创建对像的几种方式
1、new关键字
通过调用类的构造方法创建对象
2、反射
通过反射创建对象的方式又有两种 一种是通过Class.newInstance
另一种是通过调用构造器再去创建对象Constructor.newInstance 先通过反射获取类中无参构造器然后通过newInstance()获取对象
3、clone
通过Clone创建对象首先实体类中必须先实现Cloneable接口并复写Object的clone方法因为Object的这个方法是protected的
4、反序列化
序列化指把 Java 对象转换为字节序列的过程 反序列化指把字节序列恢复为 Java 对象的过程 此方式需要类先实现Serializable接口
public class UserParam implements Serializablepublic class Test {public static void main(String[] args) throws IOException, ClassNotFoundException {File file new File(E:/Serializable.txt);FileOutputStream fileOutputStream new FileOutputStream(file);ObjectOutputStream outputStream new ObjectOutputStream(fileOutputStream);UserParam userParam new UserParam(aaaa);outputStream.writeObject(userParam);FileInputStream fileInputStream new FileInputStream(file);ObjectInputStream objectInputStream new ObjectInputStream(fileInputStream);UserParam userParam1 (UserParam)objectInputStream.readObject();userParam1.setNickName(bbbbbbb);System.out.println(userParam1);}}通过阅读上面介绍的几种创建对象的方法大家一定对new、newInstance背后的工作产生了好奇那么下面我将介绍创建一个对象的流程
2、创建过程
当Java虚拟机遇到一条字节码new指令时
步骤 1、检查类是否已经被加载
去常量池中查找该引用所指向的类有没有被虚拟机加载如果没有被加载那么会进行类的加载过程。类的加载过程需要经历加载、链接、初始化三个阶段。对象的大小在类加载完成时确定。 jdk1.8中运行时常量池、类常量池存在于方法区中。
步骤 2、 为对象分配内存空间
JVM为对象分配空间即把一块确定大小的内存块从Java堆中划分出来。
1、指针碰撞
假设Java堆中内存是绝对规整的所有被使用过的内存都被放在一边空闲的内存被放在另一边中间放着一个指针作为分界点的指示器那所分配内存就仅仅是把那个指针向空闲空间方向挪动一段与对象大小相等的距离。
正常状态 为对象分配内存
这种方式的优点是工作简单效率高只需要移动指针就可以分配内存空间。
缺点也很明显由于用指针碰撞分配内存空间分为两步1、读取指针当前的位置 2、根据自身大小移动指针不是原子操作对象创建在虚拟机中是非常频繁的操作在并发情况下会导致执行读操作或执行写操作的结果与预设的结果不一致指针划分不一致。 例如线程A要给对象分配8kb读取到指针当前的位置时间片用完切换到线程B线程B要给它的对象分配16kb也读取到指针当前的位置和线程A读取到的一样将指针向空闲内存方向移动16kb大小,线程B时间片用完切换到线程A继续执行由于线程A使用的指针位置还是之前读到的。线程不安全问题
针对指针碰撞线程不安全有两种方案
同步处理加锁分配内存空间行为 采用 CAS 分配重试的方式来保证更新操作的原子性 把内存分配行为按照线程划分在不同的内存空间进行 即每个线程在Java堆中预先分配一小块内存称为本地线程分配缓冲Thread Local Allocation BufferTLAB哪个线程要分配内存就在哪个线程的本地缓冲区中分配只有本地缓冲区用完 了分配新的缓存区时才需要同步锁定虚拟机是否使用TLAB可以通过-XX/-UseTLAB参数来 设定。 2、空闲列表
如果Java堆中的内存并不是规整的 已被使用的内存和空闲的内存相互交错在一起那就没有办法简单地进行指针碰撞了虚拟机就必须维护一个列表记录上哪些内存块是可用的在分配的时候从列表中找到一块足够大的空间划分给对象实例并更新列表上的记录。
选择哪种分配方式
两种方式的选择由 Java 堆是否规整决定Java 堆是否规整是由选择的垃圾收集器是否具有压缩整理能力决定的。
步骤3、将内存空间初始化为零值
内存分配完成之后虚拟机必须将分配到的内存空间但不包括对象头都初始化为零值。零值初始化意思就是对对象的字段赋0值或者null值这也就解释了为什么这些字段在不需要进程初始化时候就能直接使用。 如果使用了TLAB的话这一项工作也可以提前至TLAB分配时顺便进行。
步骤4、对对象进行必要的设置
例如这个对象是哪个类的实例、如何才能找到类的元数据信息、对象的哈希码、对象的GC分代年龄等信息。这些信息存放在对象的对象头中。
从虚拟机的视角来看一个新的对象已经产生了。但是从Java程序的视角看来对象创建才刚刚开始——构造函数即Class文件中的()方法还没有执行所有的字段都为默认的零值对象需要的其他资源和状态信息也还没有按照预定的意图构造好。
步骤5、执行实例的初始化方法init
init方法包含成员变量、构造代码块的初始化按照声明的顺序执行执行对象的构造 方法并把堆内对象的首地址赋值给引用变量。至此对象创建成功。
总结 注意
并发情况下需要考虑操作的步骤是不是原子性如果不是就要加锁。原子性就是动作不能再继续被拆分了读是原子性写也是原子性但是读写就不是原子性