“代码编译的结果从本地机器码转变为字节码,是存储格式发展的一小步,却是变成语言发展的一大步”,这句话出自《深入理解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 init
123

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类。当程序主动使用任何一个类时,系统会保证该类以及所有的父类都会被初始化。

JAVA类加载机制详解的更多相关文章

  1. Java 类加载机制详解

    一.类加载器 类加载器(ClassLoader),顾名思义,即加载类的东西.在我们使用一个类之前,JVM需要先将该类的字节码文件(.class文件)从磁盘.网络或其他来源加载到内存中,并对字节码进行解 ...

  2. Java类加载器详解

    title: Java类加载器详解date: 2015-10-20 18:16:52tags: JVM--- ## JVM三种类型的类加载器- 我们首先看一下JVM预定义的三种类型类加载器,当一个 J ...

  3. JVM类加载机制详解(二)类加载器与双亲委派模型

    在上一篇JVM类加载机制详解(一)JVM类加载过程中说到,类加载机制的第一个阶段加载做的工作有: 1.通过一个类的全限定名(包名与类名)来获取定义此类的二进制字节流(Class文件).而获取的方式,可 ...

  4. JVM类加载机制详解

    引言 如下图所示,JVM类加载机制分为五个部分:加载,验证,准备,解析,初始化,下面我们就分别来看一下这五个过程. 加载 在加载阶段,虚拟机需要完成以下三件事情: 1)通过一个类的全限定名来获取定义此 ...

  5. Java 反射机制详解(下)

    续:Java 反射机制详解(上) 三.怎么使用反射 想要使用反射机制,就必须要先获取到该类的字节码文件对象(.class),通过字节码文件对象,就能够通过该类中的方法获取到我们想要的所有信息(方法,属 ...

  6. Java 反射机制详解(上)

    一.什么是反射 JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意方法和属性:这种动态获取信息以及动态调用对象方法的功能称为java ...

  7. java异常处理机制详解

    java异常处理机制详解 程序很难做到完美,不免有各种各样的异常.比如程序本身有bug,比如程序打印时打印机没有纸了,比如内存不足.为了解决这些异常,我们需要知道异常发生的原因.对于一些常见的异常,我 ...

  8. Java SPI机制详解

    Java SPI机制详解 1.什么是SPI? SPI 全称为 (Service Provider Interface) ,是JDK内置的一种服务提供发现机制.SPI是一种动态替换发现的机制, 比如有个 ...

  9. Java程序员的必备知识-类加载机制详解

    类加载器的概念 类加载器是一个用来加载类文件的类. Java源代码通过javac编译器编译成类文件.然后JVM来执行类文件中的字节码来执行程序.类加载器负责加载文件系统.网络或其他来源的类文件. JV ...

随机推荐

  1. typecho流程原理和插件机制浅析(第二弹)

    typecho流程原理和插件机制浅析(第二弹) 兜兜 393 2014年04月02日 发布 推荐 1 推荐 收藏 14 收藏,3.7k 浏览 上一次说了 Typecho 大致的流程,今天简单说一下插件 ...

  2. MBR中“起始磁头/扇区/柱面“同"逻辑区块地址(LBA)"的区别

    "起始磁头/扇区/柱面"共有3个字节,最大能表示8G的扇区编号.当硬盘扇区编号多于8G时,此表示法便力不从心,便使用4个字节的LBA表示法(逻辑扇区地址,相对扇区地址). 算是计算 ...

  3. 使用 Linux 搭建 VPN

    http://blog.csdn.net/catoop/article/details/7537012 VPN服务器的配置与应用 实验场景 通过将Linux配置VPN服务器允许远程计算机能够访问内网. ...

  4. 新建android项目报错,代码中找不到错误

    通过网上资料的引导,做以下操作: 1.进入C:\Documents and Settings\Administrator\.android 删除路径下的debug.keystore及 ddms.cfg ...

  5. 处理PHP字符串的10个简单方法;mysql出现乱码:character_set_server=utf8

    PHP处理字符串的能力非常强大,方法也是多种多样,但有的时候你需要选择一种最简单且理想的解决方法.文章列举了10个PHP中常见的字符串处理案例,并提供了相对应的最理想的处理方法. 1.确定一个字符串的 ...

  6. 哈哈,好像swift 以后有可能用来开发安卓喔

    好像swift  以后有可能用来开发安卓喔,哈哈

  7. HBase的数据迁移(含HDFS的数据迁移)

    1.启动两个HDFS集群 hadoop0,hadoop1,都是伪分布式的集群 2.启动hadoop3的zookeeper与hbase 注意点:需要开启yarn服务,因为distcp需要yarn. 3. ...

  8. php--http与https的区别

    在URL前加https://前缀表明是用SSL加密的.你的电脑与服务器之间收发的信息传输将更加安全. Web服务器启用SSL需要获得一个服务器证书并将该证书与要使用SSL的服务器绑定. http和ht ...

  9. RepositoryItemComboBox 用法1

    RepositoryItemComboBox cbbEnd = new RepositoryItemComboBox(); cbbEnd.TextEditStyle = DevExpress.Xtra ...

  10. 20145211 《Java程序设计》实验报告二:Java面向对象程序设计

    实验要求 初步掌握单元测试和TDD 理解并掌握面向对象三要素:封装.继承.多态 初步掌握UML建模 熟悉S.O.L.I.D原则 了解设计模式 实验内容 单元测试 面向对象三要素 设计模式初步 练习 实 ...