首页 > 编程知识 正文

深入java虚拟机之类加载机制,可以在java虚拟机中运行

时间:2023-12-28 21:11:06 阅读:329183 作者:WPEQ

本文目录一览:

java 类加载机制有什么用

AVA类加载机制详解

“代码编译的结果从本地机器码转变为字节码,是存储格式发展的一小步,却是变成语言发展的一大步”,这句话出自《深入理解JAVA虚拟机》一书,后面关于jvm的系列文章主要都是参考这本书。

JAVA源码编译由三个过程组成:

1、源码编译机制。

2、类加载机制

3、类执行机制

我们这里主要介绍编译和类加载这两种机制。

一、源码编译

代码编译由JAVA源码编译器来完成。主要是将源码编译成字节码文件(class文件)。字节码文件格式主要分为两部分:常量池和方法字节码。

二、类加载

类的生命周期是从被加载到虚拟机内存中开始,到卸载出内存结束。过程共有七个阶段,其中到初始化之前的都是属于类加载的部分

加载----验证----准备----解析-----初始化----使用-----卸载

系统可能在第一次使用某个类时加载该类,也可能采用预加载机制来加载某个类,当运行某个java程序时,会启动一个java虚拟机进程,两次运行的java程序处于两个不同的JVM进程中,两个jvm之间并不会共享数据。

1、加载阶段

这个流程中的加载是类加载机制中的一个阶段,这两个概念不要混淆,这个阶段需要完成的事情有:

1)通过一个类的全限定名来获取定义此类的二进制字节流。

2)将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。

3)在java堆中生成一个代表这个类的Class对象,作为访问方法区中这些数据的入口。

由于第一点没有指明从哪里获取以及怎样获取类的二进制字节流,所以这一块区域留给我开发者很大的发挥空间。这个我在后面的类加载器中在进行介绍。

2、准备阶段

这个阶段正式为类变量(被static修饰的变量)分配内存并设置类变量初始值,这个内存分配是发生在方法区中。

1、注意这里并没有对实例变量进行内存分配,实例变量将会在对象实例化时随着对象一起分配在JAVA堆中。

2、这里设置的初始值,通常是指数据类型的零值。

private static int a = 3;

这个类变量a在准备阶段后的值是0,将3赋值给变量a是发生在初始化阶段。

3、初始化阶段

初始化是类加载机制的最后一步,这个时候才正真开始执行类中定义的JAVA程序代码。在前面准备阶段,类变量已经赋过一次系统要求的初始值,在初始化阶段最重要的事情就是对类变量进行初始化,关注的重点是父子类之间各类资源初始化的顺序。

java类中对类变量指定初始值有两种方式:1、声明类变量时指定初始值;2、使用静态初始化块为类变量指定初始值。

初始化的时机

1)创建类实例的时候,分别有:1、使用new关键字创建实例;2、通过反射创建实例;3、通过反序列化方式创建实例。

new Test();

Class.forName(“com.mengdd.Test”);

2)调用某个类的类方法(静态方法)

Test.doSomething();

3)访问某个类或接口的类变量,或为该类变量赋值。

int b=Test.a;

Test.a=b;

4)初始化某个类的子类。当初始化子类的时候,该子类的所有父类都会被初始化。

5)直接使用java.exe命令来运行某个主类。

除了上面几种方式会自动初始化一个类,其他访问类的方式都称不会触发类的初始化,称为被动引用。

1、子类引用父类的静态变量,不会导致子类初始化。

public class SupClass

{    public static int a = 123;

static

{

System.out.println("supclass init");

}

}public class SubClass extends SupClass

{    static

{

System.out.println("subclass init");

}

}public class Test

{    public static void main(String[] args)

{

System.out.println(SubClass.a);

}

}

执行结果:

supclass init123

2、通过数组定义引用类,不会触发此类的初始化

public class SupClass

{    public static int a = 123;

static

{

System.out.println("supclass init");

}

}public class Test

{    public static void main(String[] args)

{

SupClass[] spc = new SupClass[10];

}

}

执行结果:

3、引用常量时,不会触发该类的初始化

public class ConstClass

{    public static final String A=  "MIGU";

static

{

System.out.println("ConstCLass init");

}

}public class TestMain

{    public static void main(String[] args)

{

System.out.println(ConstClass.A);

}

}

执行结果:

MIGU

用final修饰某个类变量时,它的值在编译时就已经确定好放入常量池了,所以在访问该类变量时,等于直接从常量池中获取,并没有初始化该类。

初始化的步骤

1、如果该类还没有加载和连接,则程序先加载该类并连接。

2、如果该类的直接父类没有加载,则先初始化其直接父类。

3、如果类中有初始化语句,则系统依次执行这些初始化语句。

在第二个步骤中,如果直接父类又有直接父类,则系统会再次重复这三个步骤来初始化这个父类,依次类推,JVM最先初始化的总是java.lang.Object类。当程序主动使用任何一个类时,系统会保证该类以及所有的父类都会被初始化。

JVM之class加载过程

java虚拟机把描述类的数据从class文件加载到内存,并对数据进行 校验/准备/解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这个过程被称作虚拟机的类加载机制。

称作虚拟机的类加载机制。

loading - linking (verification - preparation - resolution)- resolution)-initializing

loading: 把class文件load到内存中,采用双亲委派,主要是为了安全性

verification: 校验class文件是否符合标准

preparation: 静态变量分配内存并设初始值的阶段(不包括实例变量)

resolution:把符号引用转换为直接引用

initializing:静态变量赋初始值

类加载的过程主要分为三个部分:加载、连接、初始化这三个阶段。

类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个这个类的java.lang.Class对象,用来封装类在方法区类的对象。主要步骤可以分为下面的三件事情:

加载阶段完成后,虚拟机外部的 二进制字节流就按照虚拟机所需的格式存储在方法区之中,而且在Java堆中也创建一个java.lang.Class类的对象,这样便可以通过该对象访问方法区中的这些数据。

类的加载的最终产品是位于堆区中的Class对象。Class对象封装了类在方法区内的数据结构,并且向Java程序员提供了访问方法区内的数据结构的接口。加载类的方式有以下几种:

2.加载器

JVM的类加载是通过ClassLoader及其子类来完成的,类的层次关系和加载顺序可以由下图来描述:

1.BootstrapClassLoader(启动类加载器)

在连接里面又可以被分成3个小阶段,分别是:验证,准备,解析

1.验证(目的):

2.验证内容:

验证是连接阶段的第一步,这一阶段的目的是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。验证阶段大致会完成4个阶段的检验动作:

验证阶段是非常重要的,但不是必须的,它对程序运行期没有影响,如果所引用的类经过反复验证,那么可以考虑采用-Xverifynone参数来关闭大部分的类验证措施,以缩短虚拟机类加载的时间。

3.准备:

在准备阶段,为静态变量的初值为jvm默认的初值,而不是我们在程序中设定的初值。jvm默认为静态变量的初值是这样的

4.解析:

这一阶段的任务就是把常量池中的符号引用转换为直接引用 什么是符号引用,什么是直接引用。

1.工作内容:

JVM负责主要对类变量(类变量就是static修改的变量)进行初始化这里主要对类变量(类变量就是static修改的变量)进行初始化,初始化主要有两个方式:

2.初始化时机:

类初始化时机:只有当对类的主动使用的时候才会导致类的初始化,类的主动使用包括以下六种:

3.初始化顺序:

如果有父类,则顺序是:父类static方法/static变量赋值 – 子类static方法/static变量赋值

三、结语:

上面介绍的就是类(class)的加载,包含它的加载、链接、初始化。

Android进阶知识点,我最近整理了许多,里面讲解的非常详细。取

技术进阶手册丶面试题纲丶核心笔记资料。

描述一下JVM加载class文件的原理?

Java语言是一种具有动态性的解释型语言,类(class)只有被加载到JVM中后才能运行。当运行指定程序时,JVM会将编译生成的.class文件按照需求和一定的规则加载到内存中,并组织成为一个完整的Java应用程序。这个加载过程是由类加载器来完成的,具体来说,就是由ClassLoader和它的子类来实现的。类加载器本身也是一个类,其实质是把类文件从硬盘读取到内存中。

类的加载方式分为隐式加载与显式加载两种。隐式加载指的是程序在使用new等方法创建对象时,会隐式地调用类的加载器把对应的类加载到JVM中。显式加载指的是通过直接调用class.forName()方法来把所需要的类加载到JVM中。

任何一个工程项目都是由许多个类组成的,当程序启动时,只把需要加载的类加载到JVM中,其他类只有被使用到的时候才会被加载,采用这种方法,一方面可以加快加载速度,另外一方面可以节约程序运行过程中对内存的开销。此外,在Java语言中,每个类或接口都对应一个.class文件,这些文件可以被看成一个个可以被动态加载的单元,因此当只有部分类被修改时,只需要重新编译变化的类即可,而不需要重新编译所有文件,因此加快了编译速度。

java虚拟机字节码执行和类加载机制有什么关系

没什么关系

编译成.class是为了在不同平台的虚拟机上都能运行

类的加载机制则是语言特性方面的东西

这俩不是一个体系的概念,不应该放在一起讨论

深入java虚拟机,绝版和深入理解Java虚拟机:JVM高级特性与最佳实践。

市面上关于jvm的书少之又少,要不是周志明出的这本深入理解java虚拟机,那么中文jvm的书籍可以说是有10年的空隙了,上一版还是02年的《java虚拟机规范》了。x0dx0a从时效上来说,《深入java虚拟机》出自2000年,技术上已然是滞后很多了。x0dx0a所以这两者比较,绝对推荐后者。x0dx0ax0dx0a另外单《深入理解java虚拟机》一书来评价,绝对算是一本好书了,掌握此书内容后,基本可以解决java程序员日常遇到的虚拟机先关问题(OOM,调优,GC等),以及应付各种关于该条目的面试笔试问题。x0dx0a其中,java内存管理,类加载机制,垃圾回收建议重点阅读x0dx0ax0dx0a国外的了解不多,但是就目前来看,建议楼主先吃透周志明老师的这本。有基础还想深入的话,java虚拟机规范这种官方标准文档放着呢。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。