java创建对象的过程详解
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
java创建对象的过程详解(从内存角度分析)
java对象的创建操作其实我在《JVM系列之类的加载机制》一文曾经提到过,包含两个过程:类的初始化和实例化。为此为了理解的深入,我们还需要再来看一下类的生命周期。一张图表示:
从上面我们可以看到,对象的创建其实包含了初始化和使用两个阶段。有了这个印象之后,我们就能开始今天的文章了。先给出这篇文章的大致脉络:
首先,介绍一下java中对象的创建基本知识然后,介绍一下对象初始化的顺序接下来,介绍一下创建对象的几种方式最后,进行一个总结。(从内存角度去分析:重点)重点
一、基本知识
我们知道,一个对象的创建过程前端的学习都是需要不断的学习,学一天停一停相当于白学,学习效果很差,如果你想有人一起学习可以来这个扣裙,首先是
132 中间是667最后是127 都是零基础的同学,大家相互鼓励共同努力只是学着玩就不建议来了!!!包含两个过程:初始化和实例化
我们在使用一个对象时,JVM首先会检查相关类型是否已经加载并初始化,如果没有,则JVM立即进行加载并调用类构造器完成类的初始化。在类初始化过程中或初始化完毕后,根据具体情况才会去对类进行实例化。
实例化时候,java虚拟机就会为其分配内存来存放自己及其从父类继承过来的实例变量。在为这些实例变量分配内存的同时,这些实例变量先会被赋予默认值(零值)。在内存分配完成之后,Java虚拟机才会对新创建的对象赋予我们程序员给定的值。
小结:创建一个对象包含下面两个过程:
1、类构造器完成类初始化(分配内存、赋予默认值)
2、类实例化(赋予给定值)
二、类初始化
下面我们直接给出一个例子看一下java是如何初始化的。我们知道一个类中,往往包含静态变量、静态代码块、变量、普通方法、构造方法等信息。那么他们是如何初始化的呢?
输出:
上面这个例子比较简单,我们再来看看带有父类和接口的情况。第一步:定义一个父类
第二步:定义一个子类实现
第三步:看结果
小结,类的初始化顺序,这样看确实不好记,不过没有继承关系的我们都能很好的看到。带继承关系的,使用网上一张图来表示:
OK,类的初始化中的知识点基本上就是初始化的顺序。
三、创建对象的几种方式
其实对象的初始化就是在创建对象的时候由jvm完成的。对于创建对象,主要是研究创建对象的几种方式。下面一一的解答.这里给出6种方式,面试的时候足够你zhuangbility。
1.使用new关键字
2.Class对象的newInstance()方法
3.构造函数对象的newInstance()方法
4.对象反序列化
5.Object对象的clone()方法
6.使用Unsafe类创建对象
7.最后再揭晓。。。
OK,先认识一个,下面一个一个看。
(1)使用new关键字
(2)class的newInstance()方法
首先我们通过Class.forName()动态的加载类的Class对象,
然后通过newInstance()方法获得Test类的对象
(3)构造函数的newInstance()方法
类Constructor也有newInstance方法,这一点和Class有点像。从它的名字可以看出它与Class的不同,Class是通过类来创建对象,而Constructor则是通过构造器。
(4)序列化
首先我们要对Test实现Serializable接口。然后开始序列化数据。最后得到反序列化的对象。
(5)clone方式
Object对象中存在clone方法,它的作用是创建一个对象的副本。
(6)使用Unsafe类创建对象
Unsafe类使Java拥有了像C语言的指针一样操作内存空间的能力,同时也带来了指针的问题。过度的使用Unsafe类会使得出错的几率变大,因此Java官
方并不建议使用的,官方文档也几乎没有。Oracle正在计划从Java 9中去掉Unsafe类,如果真是如此影响就太大了。
我们无法直接创建Unsafe对象。这里我们使用反射方法得到
拿到这个对象后,调用其中的native方法allocateInstance 创建一个对象实例Object event = unsafe.allocateInstance(Test.class);
四、总结
我们想要创建一个对象。基本上就是java虚拟机分配内存的过程。因此我们可以先回顾一下java程序的执行过程。给一张网上的图,写的很清晰
一个例子去解释:(摘自我之前的文章《java8的内存结构》)
然后我们测试一下:
我们分析一下这个过程
第一步,JVM去方法区寻找Test类的代码信息,如果有直接调用,没有的话使用类的加载机制把类加载进来。同时把静态变量、静态方法、常量加载进来。这里加载的是(“冯冬冬的IT技术栈”,“冯XX”);这是因为字符串是常量,age中的18是基本类型。
第二步,jvm进入main方法,看到Person person=new Person()。首先分析Person这个类,同样的寻找Person类的代码信息,有就加载,没有的话类加载机制加载进来。同时也加载静态变量、静态方法、常量(“我正在走路。。。”)
第三步,jvm接下来看到了person,person在main方法内部,因而是局部变量,存放在栈空间中。
第四步,jvm接下来看到了new Person()。new出的对象(实例),存放在堆空间中。
第五步,jvm接下来看到了“=”,把new Person的地址告诉person变量,person通过四字节的地址(十六进制),引用该实例。是不是有点晕,别着急,画个图看一下。
第六步,jvm看到 = “冯冬冬的IT技术栈”;person通过引用new Person实例的name属性,该name属性通过地址指向常量池的"冯冬冬的IT技术栈"。