Java 类加载和实例化对象的过程

news2024/11/19 7:27:01

1. 类加载实例化过程

  1. 当我们编写完一个*.java类后。
  2. 编译器(如javac)会将其转化为字节码。
  3. 转化的字节码存储在.class后缀的文件中(.class 二进制文件)。
  4. 接下来在类的加载过程中虚拟机JVM利用ClassLoader读取该.class文件将其中的字节码加载到内存中。
  5. 基于这些字节码信息创建相应的Class Object.
  6. 每个类在JVM中只加载一次,故而每个类都对应着一个唯一的Class对象(Class Object).
  7. 这个对象包含了类的元信息(metadata),如类的名称、包名、父类、实现的接口、字段、方法、构造函数等。 
  8. class Objcect可以通过获取构造函数创建实例化的对象。

2. 类加载存储位置

  • 字节码文件:
    是Java源代码编译后的产物,它们以二进制的形式存储在文件系统中。 所以它并不存放于JVM的结构中。
  • Class Object:
    Class对象被存储在JVM的方法区(Method Area)中的元空间(Metaspace)里。
  • 实例化对象:
    存放于堆内存(Heap Memory) 

3.  JVM利用classloader进行类加载和类初始化的区别

在Java中,类加载(Class Loading)和类初始化(Class Initialization)是两个不同的阶段,它们在类生命周期中扮演着不同的角色。下面是这两个阶段的区别: 

  • 类加载(Loading):
    通过类的全名获取类的二进制数据。将这些数据转换成方法区的运行时数据结构。在内存中生成一个代表这个类的java.lang.Class对象,作为这个类的各种数据的入口。然而,类的初始化(即执行静态初始化代码和静态初始化块)是在类加载的最后阶段(初始化阶段)由 JVM 自行完成的。所以我们在使用类反射,如User.class 获取class对象时,它是不会去执行静态代码块的。
  • 类初始化(Class Initialization)
    类初始化,广义上将它类加载过程中的最后一步,只不过这一步是动态的,而不是由程序启动之初就加载的,只有当类被主动使用时才会发生。这个阶段会执行类的静态初始化代码(在声明类变量时指定的初始值和在静态代码块中指定的代码)。这个过程只会在JVM首次主动使用类时发生一次。

4. 结合第三点,补充说明为什么反射中Object.class 不加载静态代码块,而Class.forName("ClassName")会加载静态代码块 

Object.class 和 Class.forName("ClassName") 在触发类加载和初始化方面有不同的行为,这主要是因为它们使用的方式和上下文不同。

Object.class:
当你使用 Object.class 时,你实际上是在引用Java的根类Object的Class对象。由于Object类是Java运行时系统的一部分,并且它几乎总是在你开始执行任何Java代码之前就已经被加载和初始化了(因为其他所有的类都直接或间接地继承自Object类),所以当你引用Object.class时,它不会再次触发Object类的加载和初始化。 静态代码块只会在类首次被主动使用时执行,而由于Object类几乎总是已经在使用之前就被加载和初始化了,因此通过Object.class引用它不会再次触发静态代码块的执行。
Class.forName("ClassName"):
Class.forName("ClassName") 是一个用于动态加载类并触发其初始化的方法。当你调用这个方法并传入一个类名(作为字符串)时,JVM会尝试找到并加载这个类。如果类还没有被加载和初始化,JVM会首先加载这个类,然后触发其初始化过程,这包括执行静态代码块。 Class.forName() 方法的主要用途是在运行时动态地加载和使用类,而不需要在编译时就知道这个类的存在。由于它是在运行时动态加载类的,所以它总是会触发类的加载和初始化过程(如果类还没有被加载和初始化的话)。
总结来说,Object.class 不会运行静态代码块是因为Object类通常在你开始执行任何Java代码之前就已经被加载和初始化了,而Class.forName("ClassName") 会运行静态代码块是因为它用于在运行时动态地加载和初始化类。

5. 关于静态代码块初始化的几个关键点:

执行时机:静态代码块在类被加载到JVM时执行。这通常发生在类的第一次主动使用时,例如创建类的实例、访问类的静态字段或方法、反射调用类的方法等。 执行顺序:如果有多个静态代码块,它们将按照在源文件中出现的顺序执行。 与静态变量的关系:静态变量可以在静态代码块中初始化,也可以在声明时直接赋值。但是,如果静态变量在声明时直接赋值,那么该赋值操作会在静态代码块之前执行。 静态代码块与构造器:静态代码块在构造器之前执行。这是因为静态代码块属于类级别的初始化,而构造器属于对象级别的初始化。 线程安全:虽然静态代码块只执行一次,但在多线程环境下,JVM会确保静态代码块的线程安全性,即静态代码块会同步执行,不会被多个线程同时访问。但是,请注意,静态代码块中的代码本身并不是线程安全的,你仍然需要确保其中的代码在多线程环境下能够正确运行。 

6. 类中的静态代码块被初始化后保存在JVM的哪里?

在JVM中,类中的静态代码块(static code block)在初始化后被执行,但它们本身并不直接“保存”在JVM的某个特定区域。静态代码块中的代码逻辑在类加载时被执行一次,并且其执行结果(如静态变量的赋值)会被存储在JVM的以下区域:

  • 方法区(Method Area):
    类加载后,静态变量(包括在静态代码块中初始化的变量)会被存储在方法区中的静态变量区域。静态变量属于类变量,不属于对象实例的一部分,只会在类加载时初始化一次。
     
  • 堆内存(Heap Memory): 虽然静态代码块本身不直接存储在堆内存中,但是静态代码块中初始化的静态对象(如静态的数组、其他类的静态实例等)会存储在堆内存中。这些对象通过静态变量持有引用,静态变量则存储在方法区的静态变量区域中。
     
  • 常量池(Constant Pool):
    如果静态代码块中声明了static final常量,并且这些常量的值在编译时就能确定(即常量折叠),那么这些常量会被放入类的常量池中。常量池是方法区的一部分,用于存储编译期生成的各种字面量和符号引用。 需要注意的是,静态代码块只是类加载过程中的一个逻辑单元,用于在类加载时执行一些初始化操作。这些操作的结果(如静态变量的值)会被存储在JVM的相应区域中,而静态代码块本身并不作为一个独立的实体被保存。当类被加载并初始化后,静态代码块中的代码逻辑就完成了它的使命,后续的对象创建和方法调用都不会再次执行这些代码。 

7. java 类级别的初始化和对象级别的初始化的区别?

在Java中,类级别的初始化和对象级别的初始化是两个不同的概念,它们分别涉及类的静态部分和实例部分。以下是它们之间的主要区别:

类级别的初始化
执行时机:当类被JVM首次主动使用时,会触发类级别的初始化。这通常发生在创建类的第一个实例、访问类的静态字段或方法、或者通过反射调用类的方法等情况。
初始化内容:类级别的初始化包括执行静态代码块(static blocks)和初始化静态变量。静态代码块和静态变量的初始化顺序按照它们在源代码中出现的顺序进行。
执行次数:类级别的初始化只会在类首次被加载到JVM时执行一次,无论创建多少个类的实例,静态代码块都不会再次执行。
线程安全性:JVM会确保类级别的初始化是线程安全的,即静态代码块会同步执行,不会被多个线程同时访问。
对象级别的初始化
执行时机:当创建类的实例时,会触发对象级别的初始化。这通常通过调用类的构造函数来完成。
初始化内容:对象级别的初始化包括执行实例初始化块(instance blocks)和构造函数,以及初始化实例变量。实例初始化块和构造函数的执行顺序是:首先执行实例初始化块(按照它们在源代码中出现的顺序),然后执行构造函数。
执行次数:与类级别的初始化不同,对象级别的初始化会在每次创建类的实例时执行。
线程安全性:对象级别的初始化(即构造函数的执行)不是线程安全的。如果在多线程环境中创建类的实例,需要确保对共享资源的访问是同步的,以避免数据不一致或其他并发问题。
 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1699541.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JavaEE初阶多线程 (5)

1.锁的策略 1.1锁的策略是什么 这个锁的策略可以理解为,一种做法,相当于当你遇到锁竞争,加锁解锁,的情况你会怎么做。 乐观锁可以理解为疫情的时候比较乐观就买了最基本的物资, 买的时候非常方便 1.2乐观锁 当效率…

linux的用户管理

新建用户:1.useradd 2.passwd 完成的操作: (1)/etc/passwd添加一行 (2)/etc/shadow添加一行 (3)/etc/group添加一行 (4)创建用户家目录 (5)创建用户邮件文件 例:创建用户jerry,要求: uid:777&am…

Linux系统进程管理

系统进程管理 一、进程概述 1.1 什么是进程?进程管理需要做什么? 进程是已启动的运行实例,进程有以下组成部分: ​ 已分配内存的地址空间 ​ 进程ID ​ 程序的代码 ​ 进程状态 进程管理包括进程调度、中断处理、信号、进程…

基于 vuestic-ui 实战教程

1. 前言简介 Vuestic UI是一个基于开源Vue 3的UI框架。它是一个MIT许可的UI框架,提供了易于配置的现成前端组件,并加快了响应式和快速加载Web界面的开发。它最初于2021年5月由EpicMax发布,这就是今天的Vuestic UI。 官网地址请点击访问 体验…

半年不在csdn写博客,总结一下这半年的学习经历,coderfun的一些碎碎念.

前言 自从自己建站一来,就不在csdn写博客了,但是后来自己的网站因为资金问题不能继续维护下去,所以便放弃了自建博客网站来写博客,等到以后找到稳定,打算满意的工作再来做自己的博客网站。此篇博客用来记录自己在csdn…

SCI审稿结果也可能是剽窃的?Nature重锤:可能只是冰山一角

我是娜姐 迪娜学姐 ,一个SCI医学期刊编辑,探索用AI工具提效论文写作和发表。 近期,Nature报道了华沙生命科学大学水文学家Mikołaj Piniewski和他的同事们,针对学术界同行评审报告剽窃的调查结果。该团队披露了数十起明显的同行评…

Android单元测试实践

一、基础概念 按照Google官方建议,Android测试体系应该参照测试金字塔架构(如下图所示),App应该包含三类测试(即小型、中型和大型测试)。 图片 小型测试是指单元测试,用于验证应用的行为,一次验证一个类。中型测试是指集成测试,用于验证模块内堆栈级别之间的交互或相…

CHI协议_1

作者:someone链接:https://www.zhihu.com/question/304259901/answer/3455648666来源。 1. AMBA CHI简介 一致性总线接口(CHI)是AXI一致性扩展(ACE)协议的演进。它是Arm的AMBA总线的一部分。AMBA是一种免…

【数据结构/C语言】深入理解 双向链表

💓 博客主页:倔强的石头的CSDN主页 📝Gitee主页:倔强的石头的gitee主页 ⏩ 文章专栏:数据结构与算法 在阅读本篇文章之前,您可能需要用到这篇关于单链表详细介绍的文章 【数据结构/C语言】深入理解 单链表…

博客开始使用 Cache Master 缓存插件

明月在给大家推荐 Cache Master 插件的时候(可参考【推荐个比较纯正的缓存插件——Cache Master】一文),仅仅是在其他站点上试用了一下,今天明月正式在博客上用上了 Cache Master,没有想到对 Dragon 主题的支持竟然是出…

5月26(信息差)

🌍 珠峰登顶“堵车”后冰架断裂 5人坠崖 2人没爬上来! 珠峰登顶“堵车”后冰架断裂 5人坠崖 2人没爬上来! 🎄 Windows 11 Beta 22635.3646 预览版发布:中国大陆地区新增“微软电脑管家”应用 ✨ 成都限购解除即将满…

2024年上半年软件系统架构师考试【回忆版】

文章目录 考试时间考试地点综合知识案例分析1、微服务架构的优点和缺点2、质量属性的6个要素3、分布式锁 Redis的缺点4、MongoDB 存储矢量图的优势 论文回忆版论文一、论单元测试的设计与应用论文二、论大数据模型的设计与应用论文三、论模型驱动的架构设计及应用论文四、论云原…

设计模式10——装饰模式

写文章的初心主要是用来帮助自己快速的回忆这个模式该怎么用,主要是下面的UML图可以起到大作用,在你学习过一遍以后可能会遗忘,忘记了不要紧,只要看一眼UML图就能想起来了。同时也请大家多多指教。 装饰模式 是一种行为型模式。…

前端手写文件上传;使用input实现文件拖动上传

使用input实现文件拖动上传 vue2代码&#xff1a; <template><div><div class"drop-area" dragenter"highlight" dragover"highlight" dragleave"unhighlight" drop"handleDrop"click"handleClick&quo…

解决SpringBoot中插入汉字变成?(一秒解决)

在这里url后面加一行配置即可&useUnicodetrue&characterEncodingUTF-8即可 解释 spring.datasource.url: 这里包含了数据库的URL&#xff0c;以及额外的参数如useUnicodetrue用于启用Unicode字符集支持&#xff0c;characterEncodingUTF-8用于指定字符编码为UTF-8&…

【MinIO学习】

OSS Docker podman MinIO服务器 MinIO客户端 Bucket Object 时间同步 The difference between the request time and the servers time is too large。 URL

Linux防火墙之iptables(二)

一.SNAT策略概述 1.SNAT 策略的典型应用环境 局域网主机共享单个公网IP地址接入Internet&#xff08;私有IP不能在Internet中正常路由&#xff09; 局域共享上网 2.SNAT 策略的原理 源地址转换&#xff0c;Source Network Address Translation 修改数据包的源地址 未作SNAT转换…

搭建Harbor镜像仓库

前言 1、系统版本&#xff1a;CentOS9 2、harbor版本&#xff1a;v2.9.4 3、提前安装好docker和docker-compose&#xff0c;参考地址。我这里安装的版本是docker&#xff1a;26.1.3 docker-compose&#xff1a;v2.27.1 安装步骤 下载安装包 1、下载地址&#xff1a;ha…

基于yolov5和desnet的猫咪识别模型

前言 前段时间给学校的猫咪小程序搭建了识猫模型&#xff0c;可以通过猫咪的照片辨别出是那只猫猫&#xff0c;这里分享下具体的方案&#xff0c;先看效果图&#xff1a; 源代码在文末 模型训练 在训练服务器&#xff08;或你的个人PC&#xff09;上拉取本仓库代码。 图片数据…

moviepy入门

1. 简介 由于恶心的工作和没有规划的部门安排&#xff0c;我被排到了算法部门&#xff0c;从事和算法没有半毛钱关系的业务上&#xff0c;也就是。。。搞视频。咋说呢&#xff1f;视频这东西我没有一点基础&#xff0c;还好有前人写好的代码&#xff0c;用的是moviepy和ffmpeg…