泰安专业的网站建设,南充市房地产网官网,专业点网站制作公司,腾讯企业网页设计类初始化#xff0c;类加载#xff0c;类加载器 1. 类加载1.1. 类的加载1.2. 类的链接1.2.1. 验证1.2.2. 准备1.2.3. 解析 2. 类加载器2.1. 类加载器分为四种#xff1a;前三种为虚拟机自带的加载器。2.2. 类加载有三种方式#xff1a;2.3. **JVM类加载机制**2.4. 双亲委派… 类初始化类加载类加载器 1. 类加载1.1. 类的加载1.2. 类的链接1.2.1. 验证1.2.2. 准备1.2.3. 解析 2. 类加载器2.1. 类加载器分为四种前三种为虚拟机自带的加载器。2.2. 类加载有三种方式2.3. **JVM类加载机制**2.4. 双亲委派机制 3. 类的初始化3.1. 类的主动引用会发生类的初始化3.2. 类的被动引用不会发生类的初始化3.3. 类缓存 1. 类加载
1.1. 类的加载
类的加载指的是将类的.class文件中的二进制数据读入到内存中将其放在运行时数据区的方法区内然后在堆区创建一个 java.lang.Class对象用来封装类在方法区内的数据结构。 类的加载的最终产品是位于堆区中的 Class对象 Class对象封装了类在方法区内的数据结构并且向Java程序员提供了访问方法区内的数据结构的接口。 在加载阶段虚拟机需要完成以下三件事情 通过一个类的全限定名来获取其定义的二进制字节流。将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。在Java堆中生成一个代表这个类的 java.lang.Class对象作为对方法区中这些数据的访问入口。 加载.class文件的方式 从本地系统中直接加载通过网络下载.class文件从zipjar等归档文件中加载.class文件从专有数据库中提取.class文件将Java源文件动态编译为.class文件
1.2. 类的链接
将java类的二进制代码合并到JVM的运行状态中的过程
1.2.1. 验证
验证确保加载的类信息符合JVM规范没有安全方面的问题验证阶段大致会完成4个阶段的检验动作 文件格式验证验证字节流是否符合Class文件格式的规范例如是否以 0xCAFEBABE开头、主次版本号是否在当前虚拟机的处理范围之内、常量池中的常量是否有不被支持的类型。元数据验证对字节码描述的信息进行语义分析注意对比javac编译阶段的语义分析以保证其描述的信息符合Java语言规范的要求例如这个类是否有父类除了 java.lang.Object之外。字节码验证通过数据流和控制流分析确定程序语义是合法的、符合逻辑的。符号引用验证确保解析动作能正确执行。
1.2.2. 准备
准备正式为类变量static分配内存并设置类变量默认初始值的阶段这些内存都将在方法区中进行分配
该阶段有以下几点需要注意
1、这时候进行内存分配的仅包括类变量static而不包括实例变量实例变量会在对象实例化时随着对象一块分配在Java堆中。2、这里所设置的初始值通常情况下是数据类型默认的零值如0、0L、null、false等而不是被在Java代码中被显式地赋予的值。3、如果类字段的字段属性表中存在 ConstantValue属性即同时被final和static修饰那么在准备阶段变量value就会被初始化为ConstValue属性所指定的值。
假设一个类变量的定义为 public static int value3那么变量value在准备阶段过后的初始值为0而不是3因为这时候尚未开始执行任何Java方法而把value赋值为3的 public static指令是在程序编译后存放于类构造器 clinit方法之中的所以把value赋值为3的动作将在初始化阶段才会执行
对基本数据类型来说对于类变量static和全局变量如果不显式地对其赋值而直接使用则系统会为其赋予默认的零值而对于局部变量来说在使用前必须显式地为其赋值否则编译时不通过。对于同时被static和final修饰的常量必须在声明的时候就为其显式地赋值否则编译时不通过而只被final修饰的常量则既可以在声明时显式地为其赋值也可以在类初始化时显式地为其赋值总之在使用前必须为其显式地赋值系统不会为其赋予默认零值。对于引用数据类型reference来说如数组引用、对象引用等如果没有对其进行显式地赋值而直接使用系统都会为其赋予默认的零值即null。如果在数组初始化时没有对数组中的各元素赋值那么其中的元素将根据对应的数据类型而被赋予默认的零值。
1.2.3. 解析
解析虚拟机常量池内的符号引用常量名替换为直接引用地址的过程解析动作主要针对类或接口、字段、类方法、接口方法、方法类型、方法句柄和调用点限定符7类符号引用进行。符号引用就是一组符号来描述目标可以是任何字面量。直接引用就是直接指向目标的指针、相对偏移量或一个间接定位到目标的句柄。
2. 类加载器
2.1. 类加载器分为四种前三种为虚拟机自带的加载器。
启动类加载器BootstrapC 负责加载$JAVA_HOME中jre/lib/rt.jar里所有的class由C实现不是ClassLoader子类 扩展类加载器ExtensionJava 负责加载java平台中扩展功能的一些jar包包括$JAVA_HOME中jre/lib/ext/ *.jar或-Djava.ext.dirs指定目录下的jar包的一些jar包 应用程序类加载器AppClassLoaderJava 也叫系统类加载器负责加载classpath中指定的jar包及目录中class 用户自定义加载器 Java.lang.ClassLoader的子类用户可以定制类的加载方式
2.2. 类加载有三种方式
1、命令行启动应用时候由JVM初始化加载2、通过Class.forName()方法动态加载3、通过ClassLoader.loadClass()方法动态加载
2.3. JVM类加载机制
全盘负责当一个类加载器负责加载某个Class时该Class所依赖的和引用的其他Class也将由该类加载器负责载入除非显示使用另外一个类加载器来载入父类委托先让父类加载器试图加载该类只有在父类加载器无法加载该类时才尝试从自己的类路径中加载该类缓存机制缓存机制将会保证所有加载过的Class都会被缓存当程序中需要使用某个Class时类加载器先从缓存区寻找该Class只有缓存区不存在系统才会读取该类对应的二进制数据并将其转换成Class对象存入缓存区。这就是为什么修改了Class后必须重启JVM程序的修改才会生效
2.4. 双亲委派机制
双亲委派机制如果一个类加载器收到了类加载的请求它首先不会自己去尝试加载这个类而是把请求委托给父加载器去完成依次向上。 1、当AppClassLoader加载一个class时它首先不会自己去尝试加载这个类而是把类加载请求委派给父类加载器ExtClassLoader去完成。2、当ExtClassLoader加载一个class时它首先也不会自己去尝试加载这个类而是把类加载请求委派给BootStrapClassLoader去完成。3、如果BootStrapClassLoader加载失败例如在$JAVA_HOME/jre/lib里未查找到该class会使用ExtClassLoader来尝试加载4、若ExtClassLoader也加载失败则会使用AppClassLoader来加载5、如果AppClassLoader也加载失败则会报出异常ClassNotFoundException 好处 防止内存中出现多份同样的字节码(安全性角度) 比如加载位于 rt.jar 包中的类 java.lang.Object不管是哪个加载器加载这个类最终都是委托给顶层的启动类加载器进行加载这样就保证了使用不同的类加载器最终得到的都是同样一个 Object对象。 保证Java程序安全稳定运行
3. 类的初始化
在Java中对类变量进行初始值设定有两种方式①声明类变量时指定初始值②使用静态代码块为类变量指定初始值。
特点 执行类构造器clinit()方法的过程。 类构造器clinit()方法是由编译器自动收集类中所有类变量的赋值动作和静态代码块中的语句合并产生的。类构造器是构造类信息的不是构造该类对象的构造器 当初始化一个类时如果其父类还没有进行初始化则先触发其父类的初始化虚拟机会保证一个类的clinit()方法在多线程环境中被正确加锁和同步
3.1. 类的主动引用会发生类的初始化
当虚拟机启动会先初始化main方法所在的类new一个类的对象调用类的静态成员除了final常量和静态方法使用Java.lang.reflect包的方法对类进行反射调用初始化一个类时其父类如果没有初始化则会先初始化它的父类
3.2. 类的被动引用不会发生类的初始化
访问一个静态域时只有真正声明这个域的类才会被初始化。如通过子类引用父类的静态变量不会导致子类初始化通过数组定义类引用不会触发此类的初始化引用常量不会触发此类的初始化常量在链接阶段就存入调用类的常量池中了
3.3. 类缓存
标准的javaSE类加载器可以按要求查找类一旦某个类 被加载到类加载器中它将维持加载缓存一段时间。但是JVM垃圾回收机制可以回收这些Class对象