精华内容
下载资源
问答
  • Java 对象创建过程详解java中 对于一个初始化一个对象的代码为 Date d = new Date() 但是,在底层中的实现,是怎么执行的呢?又分为哪些步骤呢? 例如我们拥有一个这样的类 public class Test { int x= 1; ...

    Java知识点
    Java 对象创建过程详解
    在java中 对于一个初始化一个对象的代码为
    Date d = new Date()
    但是,在底层中的实现,是怎么执行的呢?又分为哪些步骤呢?
    例如我们拥有一个这样的类

    
    public class Test {
     int x= 1;
     
     public static void main(String[] args) {
      Test test = new Test();
     }
    }
    

    编译时,第6行的这段代码会生成五个步骤的字节码,分别是:

    1. new #2 //在堆里申请内存
    2. dup //复制一个引用
    3. invokespecial #3 <Test.> //调用构造方法,消耗掉一个引用
    4. astore_1 //将test 与new Test()产生的对象建立关联
    5. return //方法结束

    也就是我们平常所说的三步,申请内存,调用构造方法,建立关联
    当第一步进行完成之后,叫做对象的半初始化,值得注意的是,由于没有调用构造方法也就没有赋值,此时,对于成员变量x 来说,已经拥有空间,此时x=0,当调用完成第3步,x=1,初始化完成

    —学习于b站  马士兵说  的美团面试七连问

    展开全文
  • java-对象创建流程详解

    java-对象创建流程详解

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    展开全文
  • 普通Java对象创建过程详解类加载过程分配内存指针碰撞空闲列表初始化执行方法 Java是一门面向对象的编程语言,在Java程序运行过程中无时无刻都有对象被创建出来。在语言层面上,创建对象(例如克隆、反序列化)...


    Java是一门面向对象的编程语言,在Java程序运行过程中无时无刻都有对象被创建出来。在语言层面上,创建对象(例如克隆、反序列化)通常仅仅是一个new关键字而已,而在虚拟机中,普通的Java对象的创建又是怎样的一个过程呢?接下来我们一层层揭开面纱,探索new对象创建过程背后的秘密。

    类加载过程

    虚拟机遇到一条new指令是,首先将去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已被加载、解析和初始化过。如果没有,那必须先执行相应的类加载过程。具体的类加载过程如下:

    分配内存

    在类加载检查通过后,接下来虚拟机将为新生对象分配内存。对象所需内存的大小在类加载完成后便可完全确定(具体可看对象的内存布局)。主要有两种分配内存的方式:指针碰撞空闲列表

    指针碰撞

    假设Java堆中内存是绝对规整的,所有用过的内存都放在一边,空闲的内存放在另一边,中间放着一个指针作为分界点的指示器,那所分配内存就仅仅是把那个指针向空闲空间那边挪动一段与对象大小相等的距离即可。

    空闲列表

    如果Java堆中的内存并不是规整的,已使用的内存和空闲的内存相互交错,那就没办法简单地进行指针碰撞了,虚拟机就必须维护一个列表,记录上哪些内存块是可用的,在分配的时候从列表中找到一个足够大的空间划分给对象实例,并更新列表上的记录。

    选择哪种分配方式由Java堆是否规整决定,而Java堆是否规整又由所采用的垃圾收集器是否带有压缩整理功能决定。

    补充:如何在并发情况下解决对象创建的线程不安全问题?
    答:对象创建在虚拟机中是非常频繁的行为,即使是仅仅修改一个指针所指向的位置,在并发情况下也并不是线程安全的,可能出现正在给对象A分配内存,指针还没来得及修改,对象B又同时使用了原来的指针来分配内存的情况。解决这个问题有两种方案,
    (1)一种是对分配内存空间的动作进行同步处理-------实际上虚拟机采用CAS配上失败重试的方式保证更新操作的原子性;(2)另一种是把内存分配的动作按照线程划分在不同的空间之中进行,即每个线程在Java堆中预先分配一小块内存,称为本地线程分配缓冲(Thread Local Allocation Buffer,TLAB)。哪个线程要分配内存,就在哪个线程的TLAB上分配,只有TLAB用完并分配新的TLAB时,才需要同步锁定。

    初始化

    内存分配完成后,虚拟机需要将分配到的内存空间都初始化为零值(不包括对象头),如果使用TLAB,这一工作过程也可以提前至TLAB分配时进行。接下来,虚拟机要对对象的对象头进行必要的设置。

    执行方法

    在上述工作都完成之后,从虚拟机的视角来看,一个新的对象已经产生了,但从Java程序的视角来看,对象创建才刚刚开始-----方法还没有执行,所有的字段都还为零。一般来说,执行new指令之后会接着执行方法,把对象按照程序员的意愿进行初始化,这样一个真正可用的对象才算完全产生出来。

    参考:
    《深入理解Java虚拟机》 周志明著

    展开全文
  • Java对象创建过程详解

    千次阅读 2020-03-30 17:07:27
    本文详细介绍了Java对象创建过程,包括对象创建方式、分配内存、空间初始化、构造方法的执行等。

      本文详细介绍了Java中对象的创建过程,包括对象的创建方式、分配内存、空间初始化、构造方法的执行等。

    1 创建对象的方法有哪些?

    1. 运用New 关键字创建实例,这是最常用的创建对象方法。
    2. 运用反射,调用Java.lang.Class类当中newInstance方法。只能调用公共的无参构造函数。
    3. 运用反射,调用java.lang.reflect.Constructor类中的newInstance方法提供无参或有参实例。除了无参构造器,还可以调用有参数的/私有的/受保护的构造函数。事实上Class的newInstance方法内部调用Constructor的newInstance方法。这也是众多框架Spring、Hibernate、Struts等使用后者的原因。
    4. 调用对象的clone方法。必须先实现java.lang.Cloneable接口。
    5. 使用序列化和反序列化。必须先实现Serializable接口。
    6. 使用unsafe.allocateInstance(class)创建对象。Gson中使用到,关于unsafe详见此博客:JUC中的Unsafe类详解与使用案例

    方法1、2、3本质都会调用构造函数,都是常规的Java创建对象的new机制;而方法4、5、6不会调用构造函数。本次主要讲解调用构造函数的方式,即使用了new关键字。

    2 创建过程概述

    2.1 检查类的加载

      虚拟机遇到一条new指令时 ,首先将去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已被加载、解析和初始化过。如果没有 ,那必须先执行相应的类加载过程。

    2.2 分配内存

      在类加载检查通过后,接下来虚拟机将为新生对象分配内存。对象所需内存的大小在类加载完成后便可完全确定,为对象分配空间的任务等同于把一块确定大小的内存从Java堆中划分出来。

    2.2.1 内存分配方式

    1. 如果Java堆中内存是绝对规整的,所有用过的内存都放在一边,空闲的内存放在另一边,中间放着一个指针作为分界点的指示器,那所分配内存就仅仅是把那个指针向空闲空间那边挪动一段与对象大小相等的距离,这种分配方式称为“指针碰撞(Bump the Pointer)”。
    2. 如果Java堆中的内存并不是规整的,已使用的内存和空闲的内存相互交错,那就没有办法简单地进行指针碰撞了,虚拟机就必须维护一个列表,记录那些内存块是可用的,在分配的时候从列表中找到一块足够大的空间划分给对象实例,并更新列表上的记录,这种分配方式称为“空闲列表(Free List)”。

    选择哪种分配方式由Java堆是否规整决定,而Java堆是否规整又由所采用的垃圾收集器是否带有压缩整理功能决定。

    2.2.2 内存分配时的安全问题

      对象创建在虚拟机中是非常频繁地行为,仅仅是修改一个指针所指向的位置,在并发情况下也并不是线程安全的,可能出现正在给对象A分配内存,指针还没来得及修改,对象B又同时使用了原来的指针来分配内存的情况。
    解决这个问题有两种方案:

    1. 一种是对分配内存空间的动作进行同步处理-实际上虚拟机采用CAS配上失败冲的方式保证更新操作的原子性。
    2. 另一种是把内存分配的动作按照线程划分在不同的空间之中进行,即每个线程在Java堆中预先分配一小块内存,称为本地线程分配缓冲(Thread Local Allocation Buffer,TLAB)。那个线程要分配内存就在那个线程的TLAB上分配,只有TLAB用完并分配新的TLAB时,才需要同步锁定。虚拟机是否使用TLAB,可以通过-XX:+/-UseTLAB参数来设定。

    2.3 空间初始化

      内存分配完成后,虚拟机需要将分配到的内存空间都初始化为零值(不包括对象头), 如果使用TLAB方式分配内存 ,这一工作过程也可以提前至TLAB分配时进行。这一步操作保证了对象的实例字段在Java代码中可以不赋初始值就直接使用,程序能访问到这些字段的数据类型所对应的零值。下面是各种数据类型的初始值:

    类型 默认值
    byte (byte)0
    short (short)0
    int 0
    long 0L
    float 0.0f
    double 0.0d
    boolean false
    char '/uoooo'(null)
    reference(引用类型) null

    2.4 其他必要的设置

      接下来 ,虚拟机要对对象进行必要的设置,例如这个对象是哪个类的实例、如何才能找到类的元数据信息、对象的哈希码、对象的GC分代年龄等信息,这些信息存放在对象的对象头(Object Header ) 之中。 根据虚拟机当前的运行状态的不同,如是否启用偏向锁等,对象头会有不同的设置方式。这部分会在对象内存布局方面有讲解。

    2.5 执行< init >方法(new关键字专属)

      在上面工作都完成之后,从虚拟机的视角来看,一个新的对象已经产生了,但从Java程序的视角来看,对象创建才刚刚开始——< init >方法(实例初始化方法,类初始化方法是< clinit > )还没有执行,所有的字段都还为零值。 所以,一般来说(由字节码中是否跟随invokespecial指令所决定,不走构造器的初始化方式没有这条指令),执行new指令之后会接着 执行< init >方法(子类的< init >方法中会首先对父类< init >方法的调用),把对象按照程序员的意愿进行初始化。然后将内存地址赋给栈内存中的变量,这样一个真正可用的对象才算完全产生出来。
      特别注意,对象初始化和指向栈空间内存这两步,先后发生顺序是随机的。这对单例模式中的双重检查锁具有重要影响!可能直接导致单例模式的失效!(使用JDK1.5之后volatile关键字可以避免,但是之前的当本则无法保证!)

    3 补充:特殊方法

    3.1 < init >和< clinit >

      在Java虚拟机层面上,Java编程语言中的构造器是以一个名为< init >的特殊实例初始化方法的形式出现的。
      < init >这个方法名称是由编译器命名的, 因为它并非一个合法的Java方法名字, 不可能通过程序编码的方式实现。实例初始化方法只能在实例的初始化期间, 通过Java虚拟机的invokespecial指令来调用, 而且只能在尚未初始化的实例上调用该指令。构造器的访问权限,也会约束由该构造器所衍生出来的实例初始化方法。
    在这里插入图片描述
      一个类或者接口最多可以包含不超过一个类或接口的初始化方法, 类或者接口就是通过这个方法完成初始化的这个方法是一个不包含参数的、返回类型为void的方法,名为< clinit >。
      < clinit > 这个名字也是由编译器命名的, 因为它并非一个合法的Java方法名字, 不可能通过Java程序编码的方式直接实现。类或接口的初始化方法由Java虚拟机自身隐式调用, 没有任何虚拟机字节码指令可以调用这个方法, 它只会在类的初始化阶段中由虚拟机自身调用。
      < clinit>()方法对于类或接口来说并不是必须的,如果一个类/接口中没有静态语句块,也没有对类变量的赋值操作,或者该类声明了类变量,但没有明确使用类变量初始化语句或静态初始化语句初始化或者该类仅包含静态 final 变量的类变量初始化语句,并且类变量初始化语句是编译时常量表达式,那么编译器可以不为这个类生成< clinit>()方法。

    3.2 区别

      < init >是对象构造器方法,也就是说在程序执行 new 一个对象调用该对象类的 构造方法时才会执行< init >方法,而< clinit >是类构造器方法,也就是在jvm进行类加载—验证—解析—初始化中的初始化阶段jvm会调用< clinit >方法。
      < init >将语句块、变量初始化、调用父类的构造器等操作放到该方法中,顺序为:1.父类变量初始化块/父类语句块 2.父类构造函数 3.子类变量初始化块/子类语句块 4.子类构造函数。
      < clinit >将静态语句块、静态变量初始化等操作放到该方法中,顺序为:1.父类静态变量初始化/父类静态语句块 2.子类静态变量初始化/子类静态语句块。
      从上面可以知道变量和语句块的初始化是与代码书写的顺序一致的。因此要注意顺序,在(静态)代码块中可以使用(静态)变量,但是被使用的(静态)变量必须在(静态)代码块前面声明。
      更多< clinit >的使用和规则在类加载部分。

    3 参考

    《深入理解Java虚拟机》
    《Java虚拟机规范》

    展开全文
  • 下面小编就为大家带来一篇java存储以及java对象创建流程(详解)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
  • Java 对象的生命周期包括创建、使用和清除,本文详细介绍对象创建,在 Java 语言中创建对象分显式创建与隐含创建两种情况。 显式创建对象 对象的显式创建方式有 4 种。 1. 使用 new 关键字创建对象 这是常用的创建...
  • Java类加载及对象创建过程详解

    千次阅读 2019-06-27 08:00:00
    类加载过程 类加载的五个过程:加载、验证、准备、解析、初始化。 ... 在Java堆中生成一个代表这个类的java.lang.Class对象,作为方法区域数据的访问入口。 验证 验证阶段作用是保证Class...
  • 原理1:当使用任何方式来创建一个字符串对象s时,Java运行时(运行中JVM)会拿着这个X在String池中找是否存在内容相同的字符串对象,如果不存在,则在池中创建一个字符串s,否则,不在池中添加。 原理2:Java中...
  • java对象创建(内存模型)过程详解

    千次阅读 2017-04-09 14:35:58
    java对象创建详细过程步骤、jvm内存结构:声明对象引用和创建对象实体。类信息、对象引用、对象实体均在内存的不同区域。 内存结构 每一个java应用程序均会唯一的对应一个jvm实例,而这个jvm实例将会完成对象的内存...
  • 主要介绍了Java编程构造方法与对象创建详解,具有一定参考价值,需要的朋友可以了解下。
  • 主要介绍了Java创建内部类对象实例详解的相关资料,需要的朋友可以参考下
  • 创建对象与引用变量创建对象基本类型变量和引用类型变量的区别存储的值赋值引用数据和NULL 创建对象 ClassName objectRefVar = new ClassName(); 这条语句包含了三个部分: 创建对象 ——new ClassName(); 用new...
  • Java String面试相关问题详解,四种String对象创建机制,String本质,String与StringBuffer异同,常量池,Java内存模型;
  • Java对象序列化详解

    万次阅读 多人点赞 2016-08-10 14:47:32
    一、定义 序列化:把Java对象转换为字节序列的过程。    反序列化:把字节序列恢复为Java对象过程。二、用途 对象的序列化主要有两种用途:    1) 把对象的字节序列永久地保存到硬盘上,通常存放在一...
  • 说在前面的几句废话 前几天我的文章一直没有更新,大概断了4天左右,因为外出有事,所以给耽搁了,有朋友建议,我可以集中花几天,每天只写文章,这样以后觉得哪里不妥还可以修改,觉得言之有理就...java对象的...
  • java创建对象详解和多态问题

    千次阅读 2015-01-07 16:20:23
    一、 java 构造方法不等于创建对象而是初始化对象,new 关键字分配内存和创建对象的。  二、Test test = new Test();  有人用上面的表达式来说明...完成这两步之后,才算创建了一个完整的Java对象。  因此,
  • Java 对象的生命周期包括创建、使用和清除,本文详细介绍对象创建,在 Java 语言中创建对象分显式创建与隐含创建两种情况。 显式创建对象 对象的显式创建方式有 4 种。 1. 使用 new 关键字创建对象 这是常用的...
  • java对象之间赋值详解

    万次阅读 2016-03-29 15:47:32
     这种特殊的现象通常也叫作“别名”,是Java操作对象的一种基本方式。但假若不愿意在这种情况下出现别名,又该怎么操作呢?可放弃赋值,并写入下述代码: n1.i = n2.i;  这样便可保留两个独立的对象,而不是...
  • Hibernate中对于要持久化的Java对象在他的生命周期中需要经历以下几种状态: 1、临时状态(transient):刚刚用new语句创建,还没有被持久化,不处于session的缓存中。处于临时状态的Java对象被称为临时对象。 2、...
  • Java中Class对象详解

    万次阅读 多人点赞 2018-06-01 14:50:40
    https://blog.csdn.net/mcryeasy/article/details/52344729待优化整理 总结Class类简介  在java世界里,一切皆对象。...其实我们的实例对象就通过Class对象创建的。Java使用Class对象执行其RT...
  • Java中一切皆是对象(Object),并且所有对象都是由它们的类(Class)指定的。所以每一个对象都有一个到java.lang.Class(用于描述对象的结构)的实例的引用。 Person boss = new Person(); ...
  • JDK1.8——Java对象创建过程

    千次阅读 2020-08-16 20:22:20
    对象创建过程概述 对象的创建过程如图: 这里解释一下什么是符号引用: 符号引用: 符号引用是一个字符串,它给出了被引用的内容的名字并且可能会包含一些其他关于这个被引用项的信息——这些信息必须足以唯一的...
  • 深入理解Java对象创建过程:类的初始化与实例化

    万次阅读 多人点赞 2017-05-18 14:17:45
    在Java中,一个对象在可以被使用之前必须要被正确地初始化,这一点是Java规范规定的。...本文试图对JVM执行类初始化和实例化的过程做一个详细深入地介绍,以便从Java虚拟机的角度清晰解剖一个Java对象创建过程
  • Java Object对象详解

    千次阅读 2016-07-21 21:33:20
    面向对象的核心思想:“找合适的对象,做适合的事情”。 合适的对象: 1. 自己描述类,自己创建对象。 2. sun已经描述了好多常用的类,可以使用这些类...toString() 返回对象的描述信息 java.lang.Object@de6ced
  • Java 匿名对象详解

    千次阅读 2016-07-14 09:14:12
    匿名对象:没有名字的实体,也就是该实体没有对应的变量名引用。 二.匿名对象的用途 1,当对象对方法进行一次调用的时候,可以使用匿名对象对代码进行简化。  为什么只对方法,而不调用属性呢?因为匿名对象...
  • Context对象创建详解

    千次阅读 2016-01-21 20:53:18
    Context对象创建详解

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 139,402
精华内容 55,760
关键字:

java对象创建过程详解

java 订阅