`

JAVA类的加载

    博客分类:
  • JVM
 
阅读更多

Java类的装载、链接和初始化

加载(Loading)

按如下三步执行

  • 1.通过类的全名产生对应类的二进制数据流。(注意,如果没找到对应类文件,只有在类实际使用时才抛出错误。)
  • 2.分析并将这些二进制数据流转换为方法区(JVM 的架构:方法区、堆,栈,本地方法栈,pc 寄存器)特定的数据结构(这些数据结构是实现有关的,不同 JVM 有不同实现)。这里处理了部分检验,比如类文件的魔数的验证,检查文件是否过长或者过短,确定是否有父类(除了 Obecjt 类)。
  • 3.创建对应类的 java.lang.Class 实例(注意,有了对应的 Class 实例,并不意味着这个类已经完成了加载链链接!)。

链接(Linking)

链接的过程比加载过成复杂不少,这是实现 Java 的动态性的重要一步。分为三部分:验证,准备和解析。

  • 1.验证(verification)

    链接的第三部解析会把类中成员方法、成员变量、类和接口的符号引用替换为直接引用,而在这之前,需要检测被引用的类型正确性和接入属性是否正确(就是 public ,private 的的问题),诸如检查 final class 又没有被继承,检查静态变量的正确性等等。(注意到实际上有一部分验证过程已经在加载的过程中执行了。)

  • 2.准备(preparation)

    对类的成员变量分配空间。虽然有初始值,但这个时候不会对他们进行初始化(因为这里不会执行任何 Java 代码)。具体如下:

    所有原始类型的值都为 0。如 float: 0f, int: 0, boolean: 0(注意 boolean 底层实现大多使用 int),引用类型则为 null。值得注意的是,JVM 可能会在这个时期给一些有助于程序运行效率提高的数据结构分配空间。比如方发表(类似与 C++中的虚函数表,参见另一篇博文《Java:方法的虚分派和方法表》)。

  • 3.解析(Resolution)

    为类、接口、方法、成员变量的符号引用定位直接引用(如果符号引用先到常量池中寻找符号,再找先应的类型,无疑会耗费更多时间),完成内存结构的布局。

    这一步是可选的。可以在符号引用第一次被使用时完成,即所谓的延迟解析(late resolution)。但对用户而言,这一步永远是延迟解析的,即使运行时会执行 early resolution,但程序不会显示的在第一次判断出错误时抛出错误,而会在对应的类第一次主动使用的时候抛出错误!

    另外,这一步与之后的类初始化是不冲突的,并非一定要所有的解析结束以后才执行类的初始化。不同的 JVM 实现不同。详情见另一篇博文《Java 类加载的延迟初始化》

初始化类(Initialization)

开发 Java 时,接触最多的是对象的初始化。实际上类也是有初始化的。相比对象初始化(参见博文 Java 类的实例化),类的初始化机制要简单不少。

类的初始化也是延迟的,直到类第一次被主动使用(active use),JVM 才会初始化类。(参见博文《Java 类加载的延迟初始化》

类的初始化分两步:

  • 1.如果基类没有被初始化,初始化基类。
  • 2.有类构造函数,则执行类构造函数。

    类构造函数是由 Java 编译器完成的。它把类成员变量的初始化和 static 区间的代码提取出,放到一个的方法中。这个方法不能被一般的方法访问(注意,static final 成员变量不会在此执行初始化,它一般被编译器生成 constant 值)。同时,中是不会显示的调用基类的的,因为 1 中已经执行了基类的初始化。类的初始化还必须注意线程安全的问题。

PS:

为什么接口不能定义成员变量,而只能定义 final static 变量。

  • 1.接口是不可实例化,它的所有元素都不必是实例(对象)层面的。static 满足了这一点。
  • 2.如果接口的变量能被修改,那么一旦一个子类实现了这个接口,并修改了接口中的非 final 变量,而该子类的子类再次修改这个非 final 的变量后,造成的结果就是虽然实现了相同的接口,但接口中的变量值是不一样的。

综上述,static final 更适合于接口。

参考:《通过类字面常量解释接口常量为什么只能定义为 static final,类加载过程—Thinking in java》

分享到:
评论

相关推荐

    java类加载器

    类加载器在Java中扮演着至关重要的角色,不仅负责加载类,还维护了类的层次关系,确保了系统的稳定性和安全性。通过理解和掌握类加载器的工作原理及其不同类型的加载器,可以帮助开发者更好地管理Java应用程序的依赖...

    Java类加载器原理

    类加载器的作用不仅仅是加载类,还包括确保类的唯一性,避免重复加载,并且遵循特定的加载顺序。以下是对类加载器原理的详细解释: 1. 类加载器作用: 当JVM启动时,如果需要使用某个类,对应的类加载器会将这个类...

    java 类加载器 加密

    总结起来,Java 类加载器加密是一种增强程序安全性的技术,通过自定义类加载器和解密逻辑,可以在加载类之前对其进行加密,提高代码的保护性。同时,结合反射机制,即使类是加密状态,也能正常执行程序。这种技术常...

    Java类加载器.pdf

    - 使用`Class.forName(String className)`或`Class.forName(String className, boolean initialize, ClassLoader loader)`方法显式加载类。 - 使用`ClassLoader.loadClass(String name)`方法显式加载类。 其中,`...

    深入研究Java类加载机制 深入研究Java类加载机制

    Java中的类加载器遵循一个原则叫做“父母委托模型”,即当一个类加载器收到类加载请求时,首先将加载任务委托给父类加载器,只有当父类加载器无法完成加载时才会尝试自己加载。 这种设计模式的好处在于避免了类的...

    自定义Java类加载器

    Java类加载器是Java虚拟机(JVM)的关键组成部分,它负责查找并加载类到内存中,使得程序能够运行。自定义Java类加载器允许我们根据特定需求扩展默认的加载机制,例如,从非标准位置加载类或者实现动态加载。在Java...

    java类加载器学习三、类加载器的委托模式

    java类加载器学习三、类加载器的委托模式

    Java类加载原理解析

    除了这三种预定义的类加载器,Java还提供了一种特殊的**线程上下文类加载器(Thread Context ClassLoader)**,它允许在特定线程中加载类时使用非默认的类加载器。这在插件框架和OSGi等动态部署环境中尤其有用。 ...

    java类加载器-tomcat中的类加载器

    每个类加载器在尝试加载类时,会先委托给父类加载器,只有当父类加载器无法加载时,才会尝试自己加载。这种机制保证了Java的核心类库只被加载一次,同时也确保了类的唯一性。 Tomcat的类加载器工作流程可以总结为:...

    java类加载原理分析

    类加载的过程遵循“双亲委派模型”(Delegation Model),即当一个类加载器接收到加载类的请求时,它首先会委托其父加载器尝试加载,只有在父加载器无法加载时,自身才会尝试加载。这样设计可以避免类的重复加载,并...

    深入探讨 Java 类加载器

    当一个类加载器尝试加载类时,它会先委托给父类加载器,只有在父类加载器无法找到相应类时,子类加载器才会尝试加载。这种机制避免了类的重复加载,并且允许自定义类加载器覆盖父类加载器的行为。 线程上下文类加载...

    java类加载机制

    双亲委派模型是Java类加载器的重要特性之一,它的基本流程是:当一个类加载器收到加载类的请求时,它首先不会自己去尝试加载这个类,而是把请求委托给父类加载器去完成,每个层次的类加载器都是如此。如果父类加载器...

    Java类加载机制.doc

    例如,如果你正在开发一个需要从远程服务器获取辅助代码的系统,你可以创建一个类加载器,它可以从指定的URL加载类字节码,然后将其转换为java.lang.Class对象。这样做可以让应用程序动态地更新和使用远程服务器上的...

    Java类加载机制

    4. **自定义类加载器(Custom Class Loader)**:开发者可以根据需要创建自定义的类加载器,以便支持特殊的需求,比如从网络加载类或动态地修改字节码。 #### 五、类加载过程 类加载过程主要包括三个阶段:加载、...

    深入解析Java类加载器及其工作机制

    Java 类加载器是 Java 运行时环境中不可或缺的组成部分,负责将 .class 文件加载到 JVM 中。理解类加载器的工作原理对于深入掌握 Java 语言及其运行机制至关重要。本文将详细探讨 Java 类加载器的概念、类型以及工作...

    java类加载机制.xmind

    该文件是JVM中关于类加载机制的知识整理的思维导图,包括类加载机制概述、类加载的生命周期、加载时机、加载过程、类加载、类的初始化和实例化等几个大方面进行了讲解,其中类加载中还对JVM三种预定义类加载器进行了...

    Java类加载及SPI机制.pdf

    为了避免重复加载类和防止核心类库被篡改,Java采用了委派模式来加载类。即如果一个类加载器收到了类加载的请求,它首先不会自己尝试去加载这个类,而是将加载请求委托给父类加载器去完成,每一层都是如此,只有当...

Global site tag (gtag.js) - Google Analytics