使用某个类是发生的事情

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

加载:将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. winmail服务器启动失败 无法启动

    1.解决句柄问题:打开命令行:开始 -> 运行-> 输入 cmd -> 确定.切换命令目录至winmail的服务目录,我的是:E:\htdocs\Winmail\server\> ...

  2. Android集成支付宝的坑

    Android在集成支付宝sdk的时候, 如果有安装支付宝,则启动支付宝app进行支付: 如果没有安装,则启动 H5PayActivity 进行支付. 记得在AndroidManifest里面配置: ...

  3. Android拓展系列(9)--Android视频录制screenrecord命令

    在Android4.4 Kitkat上集成了一个比较好用的视频录制功能.参考:http://forums.androidcentral.com/android-4-4-kitkat/329674-ho ...

  4. Codeforces Round #354 (Div. 2)-C

    C. Vasya and String 题目链接:http://codeforces.com/contest/676/problem/C High school student Vasya got a ...

  5. jade学习01

    编写 简单例子 doctype html html head title learn jade body h1 learn jade 常用命令 编译: jade index.jade //默认编译成压 ...

  6. ubuntu 下python版本切换

    1. 安装ubuuntu 14.04之后python的默认版本为2.7.6但是我想使用python的版本为3.4 可以打开终端:输入:alias python = python3

  7. JS日期函数

    JS的日期函数有以下几个: getFullYear(); //获取当前年 getMonth(); //获取当前月,需要加1,而且只有一位数字,如果小于10需要前面加0 getDate(); //获取当 ...

  8. Open CV 播放视频(2)

      演示:读取一个视频,然后播放,ESC退出.   #include "stdafx.h"   #include <opencv2/core/core.hpp>   # ...

  9. Redis入门指南

    随着互联网业务对性能需求日益强烈,作为Key/Value存储的Redis具有数据类型丰富和性能表现优异的特点.如果能够熟练地驾驭它,不管是把它用做缓存还是存储,对很多大型应用都很多帮助.新浪作为世界上 ...

  10. [转]crontab环境变量设置

    原文连接:http://blog.csdn.net/zc02051126/article/details/20480289 come from http://www.360doc.com/conten ...