new一个对象的过程

java new一个对象的过程中发生了什么?

对于第一次使用该类,需要经历两个过程:(1)类加载以及初始化;(2)创建对象。

如果不是第一次使用该类,直接创建对象即可。

类加载

对于类加载,可以看我的另一篇文章“Java类加载机制”,这里简单总结一下类加载过程。

java使用双亲委派机制来进行类的加载,所谓双亲委派,就是类加载器是分层级的:根类加载器、扩展类加载器、应用加载器和用户类加载器。当一个类加载器收到类加载请求时,首先将请求委托给负类加载器去完成,层层向上传递。只有当父类加载器反馈自己无法完成该加载请求时,子类加载器才会尝试亲自去加载。

类加载过程包括以下5个步骤:

  1. 加载

    类加载器根据类全限定名寻找对应class文件, 并存储在运行时内存区的方法区,然后将其转换为一个与目标类型对应的java.lang.Class对象实例

  2. 连接

    1. 验证:包含格式验证、语义验证、操作验证等
      • 格式验证:验证是否符合class文件规范
      • 语义验证:检查一个被标记为final的类型是否包含子类;检查一个类中的final方法是否被子类进行重写;确保父类和子类之间没有不兼容的一些方法声明(比如方法签名相同,但方法的返回值不同)
      • 操作验证:在操作数栈中的数据必须进行正确的操作,对常量池中的各种符号引用执行验证(通常在解析阶段执行,检查是否可以通过符号引用中描述的全限定名定位到指定类型上,以及类成员信息的访问修饰符是否允许访问等)
    2. 准备
      • 为类中的所有静态变量分配内存空间,并为其设置一个初始值(由于还没有产生对象,实例变量不在此操作范围内)
      • 被final修饰的static变量(常量),会直接赋值;
    3. 解析
      • 将常量池中的符号引用转为直接引用(得到类或者字段、方法在内存中的指针或者偏移量,以便直接调用该方法),这个可以在初始化之后再执行。
      • 解析需要静态绑定的内容(所有不会被重写的方法和域都会被静态绑定 )。
  3. 初始化

    先初始化父类,再初始化子类。初始化主要包括以下内容:

    • 为静态变量赋值
    • 执行static代码块

最终,方法区会存储当前类类信息,包括类的静态变量类初始化代码定义静态变量时的赋值语句静态初始化代码块)、实例变量定义实例初始化代码定义实例变量时的赋值语句实例代码块构造方法)和实例方法,还有父类的类信息引用。

类创建

1、在堆区分配对象需要的内存

分配的内存包括本类和父类的所有实例变量,但不包括任何静态变量

2、对所有实例变量赋默认值

将方法区内对实例变量的定义拷贝一份到堆区,然后赋默认值

3、执行实例初始化代码

初始化顺序是先初始化父类再初始化子类,初始化时先执行实例代码块然后是构造方法

4、如果有类似于Child c = new Child()形式的c引用的话,在栈区定义Child类型引用变量c,然后将堆区对象的地址赋值给它

需要注意的是,每个子类对象持有父类对象的引用,可在内部通过super关键字来调用父类对象,但在外部不可访问

参考资料

  1. https://www.cnblogs.com/JackPn/p/9386182.html
打赏
  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!
  • Copyrights © 2021-2022 Yin Peng
  • 引擎: Hexo   |  主题:修改自 Ayer
  • 访问人数: | 浏览次数:

请我喝杯咖啡吧~

支付宝
微信