使用某个类是发生的事情

加载->链接(验证、准备、解析)->初始化->可以使用

加载:将class文件字节码内容加载到内存当中,并将这些静态数据转换成方法区中的运行时数据结构

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

链接:将java类的二进制代码合并到jvm的运行状态之中的过程

  验证:确保加载的类信息符合jvm的规范,没有安全方面的问题。(确保加载的二进制代码不会损坏jvm)。

  准备:正式为类变量(static变量,此时初始化为0,在后续的初始化时会将用户的初始化值赋给类变量)分配内存并设置变量初始值的阶段,这些内存都将在方法区中进行分配。

  解析:虚拟机常量池内的符号引用替换为直接引用的过程。(注:常量池内的内容包括类名、类内部的变量名、字符串常量等等)

初始化:

初始化阶段是执行类构造器<clinit>()方法的过程,类构造器<clinit>()方法是由编译器自动收集类中的所有类变量的赋值动作和静态语句块(static块)中的语句合并产生的(简言之,就是合并类的静态变量和静态代码块,形成类构造器进行执行)。

当初始化一个类的时候,如果发现其父类还没有进行过初始化,则需要先触发其父类的初始化

虚拟机会保证一个类的<clinit>()方法在多线程环境中被正确加锁和同步。

当访问一个java类的静态域时,只有真正声明这个域的类才会被初始化。

如下代码说明了初始化阶段为执行类构造器<clinit>()的过程,即类构造器的执行是先于类的构造方法的。

class A {
public static int width = 100; static {
System.out.println("before 静态初始化类A"+A.width);
width = 300;
System.out.println("after 静态初始化类A"+A.width);
} public A(){
System.out.println("创建A类的对象");
}
} public class Demo { public static void main(String[] args) {
A a = new A();
System.out.println(A.width); }
}

  可以看到类构造方法<clinit>()的执行在构造器之前。

下面代码则说明了当初始化一个类的时候,如果发现其父类还没有进行过初始化,则需要先触发其父类的初始化。

package com.test;

class A_Father{
static {
System.out.println("静态初始化A_Father");
}
} class A extends A_Father{
public static int width = 100; static {
System.out.println("before 静态初始化类A"+A.width);
width = 300;
System.out.println("after 静态初始化类A"+A.width);
} public A(){
System.out.println("创建A类的对象");
}
} public class Demo { public static void main(String[] args) {
A a = new A();
System.out.println(A.width); }
}

  看如下的代码分析输出

package com.test;

class A_Father{
static {
System.out.println("静态初始化A_Father");
}
} class A extends A_Father{
public static int width = 100; static {
System.out.println("before 静态初始化类A"+A.width);
width = 300;
System.out.println("after 静态初始化类A"+A.width);
} public A(){
System.out.println("创建A类的对象");
}
} public class Demo {
static{
System.out.println("静态初始化Demo");
} public static void main(String[] args) {
System.out.println("Demo的main方法");
A a = new A();
System.out.println(A.width);
A a2 = new A(); //java.lang.Class<A> aclass = A.class;
//Class aclass2 = A.class;
}
}

  输出如下:

静态初始化Demo
Demo的main方法
静态初始化A_Father
before 静态初始化类A100
after 静态初始化类A300
创建A类的对象
300
创建A类的对象

首先程序执行时要加载public的Demo类,初始化类(执行类构造方法)于是打印了“静态初始化Demo”,类初始化完成后进入方法调用,即main方法中,输出“Demo的main方法”,此时执行下一句  A a = new A();  因为A类此时尚未加载,所以首先要加载类A,然后链接初始化,初始化时发现A还有个父类没有加载呢,于是又去加载父类,链接初始化父类,打印了消息“静态初始化A_Father”,父类初始化完成了,此时类A的初始化开始,于是打印了“before 静态初始化类A100” 和“after 静态初始化类A300”,到这个时候,类已经全部加载到内存当中了,于是可以创建A的对象了,于是打印“创建A类的对象”,执行打印语句输出“300”,最后又创建了A的一个对象,但是由于类已经加载过了,所以只会调用类的构造器输出“创建A类的对象”,说明了类的加载只有一次,而类的实例化可以有多次。

关于类的加载有一个细节:

类的加载分为类的被动引用和类的主动引用,类的被动引用不会发生类的初始化,类的主动引用一定会发生类的初始化。

类的被动引用有

  1.当访问一个静态域时,只有真正声明这个域的类才会被初始化(通过子类引用父类的静态变量不会导致子类初始化,只有父类被初始化)

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

  3.引用常量不会触发此类的初始化(常量在编译阶段就存入调用类的常量池中了)

类的主动引用有

  1.new一个类的对象

  2.调用类额静态成员(除了final常量)和静态方法。

  3.使用java.lang.reflect包的方法对类进行反射调用

  4.当虚拟机启动,java Hello,则一定会初始化Hello类(直白的说就是先加载main方法所在的类)

  5.当初始化一个类,如果其父类没有被初始化,则先会初始化它的父类。

测试代码:

package com.test;

class A_Father{
static {
System.out.println("静态初始化A_Father");
}
} class A extends A_Father{
public static int width = 100;
public static final int MAX = 100;
static {
System.out.println("before 静态初始化类A"+A.width);
width = 300;
System.out.println("after 静态初始化类A"+A.width);
} public static void test(){
System.out.println("静态方法");
} public A(){
System.out.println("创建A类的对象");
}
} class B extends A{
static {
System.out.println("静态初始化B");
}
} public class Demo {
static{
System.out.println("静态初始化Demo");
} public static void main(String[] args) throws ClassNotFoundException {
System.out.println("Demo的main方法");
//主动加载
//new A();
//System.out.println(A.width);
//A.test();
//Class.forName("com.test.A"); //被动加载
//System.out.println(A.MAX);
//A[] as = new A[10];
System.out.println(B.width); }
}

  

java类加载机制的更多相关文章

  1. Java 类加载机制

    类的加载: 类的初始化: 类什么时候才被初始化:1)创建类的实例,也就是new一个对象2)访问某个类或接口的静态变量,或者对该静态变量赋值3)调用类的静态方法4)反射(Class.forName(&q ...

  2. Java类加载机制深度分析

    转自:http://my.oschina.net/xianggao/blog/70826 参考:http://www.ibm.com/developerworks/cn/java/j-lo-class ...

  3. 理解Java类加载机制(译文)

    理解java类加载机制 你想写类加载器?或者你遇到了ClassCastException异常,或者你遇到了奇怪的LinkageError状态约束异常.应该仔细看看java类的加载处理了. 什么是类加载 ...

  4. 剑指Offer——知识点储备-故障检测、性能调优与Java类加载机制

    剑指Offer--知识点储备-故障检测.性能调优与Java类加载机制 故障检测.性能调优 用什么工具可以查出内存泄露 (1)MerroyAnalyzer:一个功能丰富的java堆转储文件分析工具,可以 ...

  5. 两道面试题,带你解析Java类加载机制

    文章首发于[博客园-陈树义],点击跳转到原文<两道面试题,带你解析Java类加载机制> 在许多Java面试中,我们经常会看到关于Java类加载机制的考察,例如下面这道题: class Gr ...

  6. 【转】两道面试题,带你解析Java类加载机制(类初始化方法 和 对象初始化方法)

    本文转自 https://www.cnblogs.com/chanshuyi/p/the_java_class_load_mechamism.html 关键语句 我们只知道有一个构造方法,但实际上Ja ...

  7. Java类加载机制及自定义加载器

    转载:https://www.cnblogs.com/gdpuzxs/p/7044963.html Java类加载机制及自定义加载器 一:ClassLoader类加载器,主要的作用是将class文件加 ...

  8. Java类加载机制的理解

    算上大学,尽管接触Java已经有4年时间并对基本的API算得上熟练应用,但是依旧觉得自己对于Java的特性依然是一知半解.要成为优秀的Java开发人员,需要深入了解Java平台的工作方式,其中类加载机 ...

  9. Java类加载机制与Tomcat类加载器架构

    Java类加载机制 类加载器 虚拟机设计团队把类加载阶段中的“通过一个类的全限定名来获取描述此类的二进制字节流”这个动作放到Java虚拟机外部去实现,以便让应用程序自己决定如何去获取所需要的类.实现这 ...

  10. 带你解析Java类加载机制

      目录 Java类加载机制的七个阶段 加载 验证 准备(重点) 解析 初始化(重点) 使用 卸载 实战分析 方法论 树义有话说 在许多Java面试中,我们经常会看到关于Java类加载机制的考察,例如 ...

随机推荐

  1. Loadrunne实现多个场景运行

    如何让Loadrunne实现多个场景运行? 场景分析: 有3个不同的场景,分别为搜索,下载,上传,其中3个场景执行顺序为按照搜索->下载->上传流程操作:哪么如何让Loadrunner中如 ...

  2. hdu1710 二叉树的遍历

    Problem Description 已知前序和中序 求后序 Input The input contains several test cases. The first line of each ...

  3. DSP using MATlAB 示例Example2.10

    上代码 % noise sequence 1 x = [3, 11, 7, 0, -1, 4, 2]; nx = [-3:3]; % given signal x(n) [y,ny] = sigshi ...

  4. 如何查看经过编码的cookie?

    方法1.去在线工具网站(http://tool.oschina.net/encode?type=2)手动复制编码的cookie,转码后查看. 方法2.用火狐浏览器打开网页,如果有历史记录(存在cook ...

  5. Y86模拟器安装

    Y86模拟器安装 这周需要学习Y86下的指令集开发,Y86和x86可以说是孪生兄弟,但是还是存在着一些小的差别.接下来介绍如何进行linux-debian平台下的Y86模拟器安装. 虚拟机VMware ...

  6. android studio手动加入jar包

    点击启动AndroidStudio,启动后的界面如图所示. 复制你需要添加的jar,并将其黏贴到app— —src— —main— —libs文件夹下,可运行的AndroidStudio项目都有像这样 ...

  7. Java jar命令 常见用法

    一.jar命令作用: 进行打包 -- 把多个文件打包成一个压缩包 -- 这个压缩包和Winzip的压缩格式是一样的. 区别在于jar压缩的文件默认多一个META-INF的文件夹,该文件夹下包含一个Ma ...

  8. How to: 执行Action当收到数据时

      本文旨在演示ActionBlock的使用. 大致流程: 输入路径--读取字节--计算--传输到打印   // Demonstrates how to provide delegates to ex ...

  9. CF#335 Sorting Railway Cars

    Sorting Railway Cars time limit per test 2 seconds memory limit per test 256 megabytes input standar ...

  10. Nginx设置Js、Css等静态文件的缓存过期时间

    location ~.*\.(js|css|html|png|jpg)$ { expires 3d; } expires    3d; //表示缓存3天 expires    3h; //表示缓存3小 ...