丰都县网站,谷歌手机网页版入口,企业为什么要审计,云服务器安装网站摘要: 一个java文件从被加载到被卸载这个生命过程#xff0c;总共要经历4个阶段#xff1a; 加载-链接#xff08;验证准备解析#xff09;-初始化#xff08;使用前的准备#xff09;-使用-卸载 其中类加载过程包括加载、验证、准备、解析和初始化五个阶…摘要: 一个java文件从被加载到被卸载这个生命过程总共要经历4个阶段 加载-链接验证准备解析-初始化使用前的准备-使用-卸载 其中类加载过程包括加载、验证、准备、解析和初始化五个阶段。
类从被加载到JVM中开始到卸载为止整个生命周期包括加载、验证、准备、解析、初始化、使用和卸载七个阶段。
其中类加载过程包括加载、验证、准备、解析和初始化五个阶段。 类加载器的任务就是根据一个类的全限定名来读取此类的二进制字节流到JVM中然后转换为一个与目标类对应的java.lang.Class对象实例。 BootstrapClassLoader、ExtClassLoader和AppClassLoader defineClass方法将字节码的byte数组转换为一个类的class对象实例如果希望在类被记载到JVM时就被链接那么可以调用resolveClass方法。
自定义类加载器需要继承抽象类ClassLoader实现findClass方法该方法会在loadClass调用的时候被调用findClass默认会抛出异常。
findClass方法表示根据类名查找类对象 loadClass方法表示根据类名进行双亲委托模型进行类加载并返回类对象 defineClass方法表示跟根据类的字节码转换为类对象
双亲委托模型约定类加载器的加载机制 当一个类加载器接收到一个类加载的任务时不会立即展开加载而是将加载任务委托给它的父类加载器去执行每一层的类都采用相同的方式直至委托给最顶层的启动类加载器为止。如果父类加载器无法加载委托给它的类便将类的加载任务退回给下一级类加载器去执行加载。
双亲委托模型的工作过程是如果一个类加载器收到了类加载的请求它首先不会自己去尝试加载这个类而是把这个请求委托给父类加载器去完成每一个层次的类加载器都是如此因此所有的加载请求最终都应该传送到顶层的启动类加载器中只有当父类加载器反馈自己无法完成这个加载请求它的搜索范围中没有找到所需要加载的类时子加载器才会尝试自己去加载。 使用双亲委托机制的好处是能够有效确保一个类的全局唯一性当程序中出现多个限定名相同的类时类加载器在执行加载时始终只会加载其中的某一个类。
使用双亲委托模型来组织类加载器之间的关系有一个显而易见的好处就是Java类随着它的类加载器一起具备了一种带有优先级的层次关系。例如类java.lang.Object它存放在rt.jar之中无论哪一个类加载器要加载这个类最终都是委托给处于模型最顶端的启动类加载器进行加载因此Object类在程序的各种加载器环境中都是同一个类。相反如果没有使用双亲委托模型由各个类加载器自行去加载的话如果用户自己编写了一个称为java.lang.Object的类并放在程序的ClassPath中那系统中将会出现多个不同的Object类Java类型体系中最基础的行为也就无法保证应用程序也将会变得一片混乱。如果自己去编写一个与rt.jar类库中已有类重名的Java类将会发现可以正常编译但永远无法被加载运行。 双亲委托模型对于保证Java程序的稳定运作很重要但它的实现却非常简单实现双亲委托的代码都集中在java.lang.ClassLoader的loadClass()方法中逻辑清晰易懂先检查是否已经被加载过若没有加载则调用父类加载器的loadClass()方法若父加载器为空则默认使用启动类加载器作为父加载器。如果父类加载器加载失败抛出ClassNotFoundException异常后再调用自己的findClass方法进行加载。 1、加载 简单的说类加载阶段就是由类加载器负责根据一个类的全限定名来读取此类的二进制字节流到JVM内部并存储在运行时内存区的方法区然后将其转换为一个与目标类型对应的java.lang.Class对象实例Java虚拟机规范并没有明确要求一定要存储在堆区中只是hotspot选择将Class对戏那个存储在方法区中这个Class对象在日后就会作为方法区中该类的各种数据的访问入口。 2、链接 链接阶段要做的是将加载到JVM中的二进制字节流的类数据信息合并到JVM的运行时状态中经由验证、准备和解析三个阶段。 1、验证 验证类数据信息是否符合JVM规范是否是一个有效的字节码文件验证内容涵盖了类数据信息的格式验证、语义分析、操作验证等。 格式验证验证是否符合class文件规范 语义验证检查一个被标记为final的类型是否包含子类检查一个类中的final方法视频被子类进行重写确保父类和子类之间没有不兼容的一些方法声明比如方法签名相同但方法的返回值不同 操作验证在操作数栈中的数据必须进行正确的操作对常量池中的各种符号引用执行验证通常在解析阶段执行检查是否通过富豪引用中描述的全限定名定位到指定类型上以及类成员信息的访问修饰符是否允许访问等 2、准备 为类中的所有静态变量分配内存空间并为其设置一个初始值由于还没有产生对象实例变量不在此操作范围内 被final修饰的静态变量会直接赋予原值类字段的字段属性表中存在ConstantValue属性则在准备阶段其值就是ConstantValue的值 3、解析 将常量池中的符号引用转为直接引用得到类或者字段、方法在内存中的指针或者偏移量以便直接调用该方法这个可以在初始化之后再执行。 可以认为是一些静态绑定的会被解析动态绑定则只会在运行是进行解析静态绑定包括一些final方法(不可以重写),static方法(只会属于当前类)构造器(不会被重写) 3、初始化 将一个类中所有被static关键字标识的代码统一执行一遍如果执行的是静态变量那么就会使用用户指定的值覆盖之前在准备阶段设置的初始值如果执行的是static代码块那么在初始化阶段JVM就会执行static代码块中定义的所有操作。 所有类变量初始化语句和静态代码块都会在编译时被前端编译器放在收集器里头存放到一个特殊的方法中这个方法就是clinit方法即类/接口初始化方法。该方法的作用就是初始化一个中的变量使用用户指定的值覆盖之前在准备阶段里设定的初始值。任何invoke之类的字节码都无法调用clinit方法因为该方法只能在类加载的过程中由JVM调用。 如果父类还没有被初始化那么优先对父类初始化但在clinit方法内部不会显示调用父类的clinit方法由JVM负责保证一个类的clinit方法执行之前它的父类clinit方法已经被执行。 JVM必须确保一个类在初始化的过程中如果是多线程需要同时初始化它仅仅只能允许其中一个线程对其执行初始化操作其余线程必须等待只有在活动线程执行完对类的初始化操作之后才会通知正在等待的其他线程。
样加载过程就差不多了但是一个类要可以使用还要进行链接初始化两个过程。
加载--链接--初始化 其中链接还包括验证--准备--》解析三个过程 1、加载即上面说的整个过程 类的加载阶段主要是获取定义此类的二进制字节流并将这个字节流所代表的静态存储结构转化为方法区的运行时数据结 构最后在Java堆中生成一个代表这个类的java.lang.Class对象作为方法区这些数据的访问入口。相对于类加载过程的其他 阶段加载阶段是开发期可控性最强的阶段。我们可以通过定制不通的类加载器也就是ClassLoader来控制二进制字节流的 获取方式。 2、验证 验证准备和解析其实都属于连接阶段而验证就是连接阶段的第一步。这一阶段主要是为了确保Class文件的字节流中包含 的信息复合当前虚拟机的要求并且不会危害虚拟机自身的安全。主要验证过程包括文件格式验证元数据验证字节码验 证以及符号引用验证。 3、准备 准备阶段正式为类变量分配内存并设置初始值。这里的初始值并不是初始化的值而是数据类型的默认零值。这里提到的类 变量是被static修饰的变量而不是实例变量。关于准备阶段为类变量设置零值的唯一例外就是当这个类变量同时也被final 修饰那么在编译时就会直接为这个常量赋上目标值。 4、解析 解析时虚拟机将常量池中的符号引用替换为直接引用的过程。 5、初始化 在准备阶段变量已经赋过一次系统要求的初始值在初始化阶段则是根据程序员通过程序的主观计划区初始化类变量和其 他资源。Java虚拟机规范规定了有4种情况必须立即对类进行初始化加载验证准备必须在此之前完成 1当使用new关键字实例化对象时当读取或者设置一个类的静态字段被final修饰的除外时以及当调用一个类的静态 方法时比如构造方法就是静态方法如果类未初始化则需先初始化。 2通过反射机制对类进行调用时如果类未初始化则需先初始化。 3当初始化一个类时如果其父类未初始化先初始化父类。 4用户指定的执行主类含main方法的那个类在虚拟机启动时会先被初始化。 除了上面这4种方式所有引用类的方式都不会触发初始化称为被动引用。如通过子类引用父类的静态字段不会导致子类 初始化通过数组定义来引用类不会触发此类的初始化引用类的静态常量不会触发定义常量的类的初始化因为常量在编 译阶段已经被放到常量池中了。