背景:对java类的加载机制,一直都是模糊的理解,这篇文章看下来清晰易懂。

转载:http://blog.csdn.net/seu_calvin/article/details/52301541

1. 类加载器的组织结构

类加载器 ClassLoader是具有层次结构的,也就是父子关系。其中,Bootstrap是所有类加载器的父亲。

(1)Bootstrapclass loader: 启动类加载器

当运行Java虚拟机时,这个类加载器被创建,它负责加载虚拟机的核心类库,如java.lang.*等。

(2)Extensionclass loader:标准扩展类加载器

用于加载除了基本 API之外的一些拓展类。

(3)AppClassLoader:加载应用程序和程序员自定义的类。

运行下面的程序,结果也显示出来了:

从运行结果可以看出加载器之间的父子关系,ExtClassLoader的父Loader返回了null

原因是BootstrapLoader(启动类加载器)是用C语言实现的,找不到一个确定的返回父Loader的方式。

2. 类的加载机制

类被加载到虚拟机内存包括加载、链接、初始化几个阶段。其中链接又细化分为验证、准备、解析。

这里需要注意的是,解析阶段在某些情况下可以在初始化阶段之后再开始,这是为了支持Java的运行时绑定。各个阶段的作用整理如下:

2.1 加载阶段

加载阶段可以使用系统提供的类加载器(ClassLoader)来完成,也可以由用户自定义的类加载器完成,开发人员可以通过定义类加载器去控制字节流的获取方式。

ps:可以自定义类加载器,从加密和安全两个角度出发来加载特殊的类。具体参考——JVM——自定义类加载器

(1)通过类的全名产生对应类的二进制数据流。

(2)将这些二进制数据流转换为方法区的运行时数据结构。

(3)创建代表这个类的java.lang.Class对象。作为方法区这些数据的访问入口。

2.2 链接阶段(实现 Java 的动态性的重要一步)

(1)验证:验证阶段的主要目的是确保class文件字节流的正确性,要验证比如class文件格式规范、这个类是否继承了final类、不能把一个父类对象赋值给子类数据类型等等。

(2)准备:准备阶段为方法区中的静态变量分配内存空间。并将其赋值为初始值,所有原始类型的值都为0。如float为0f、 int为0、boolean为0、引用类型为null。

(3)解析:解析阶段把符号引用解析为直接引用。

符号引用是一个字符串,它唯一标识一个类、一个字段、一个方法等目标。

而直接引用对于类变量、类方法指的是指向方法区的指针,然后对于实例方法、实例对象来说就是偏移量,比如一个实例方法,子类中方法表中的偏移量和父类是一致的,这个偏移量可以确定某个方法的位置。

2.3 初始化

到了初始化阶段,才是真正执行用户定义的程序代码。在初始化阶段就是执行类构造器方法的过程,工作包括赋值类变量、静态语句块的合并。

//定义在静态语句块之后的变量可以赋值,但不能访问
public class Test{
static{
i=0;//給变量赋值,可以通过编译
System.out.print(i);//这句编译器会提示非法向前引用
}
static int i=1;
}

初始化过程会被触发的条件汇总:

(1)使用new关键字实例化对象、访问一个类的静态字段、静态方法的时候。

(2)对类进行反射调用的时候。

(3)当初始化子类时,如果发现其父类还没有进行过初始化,则进行父类的初始化。

【关于构造器方法拓展知识】(可以不看)

(1)类构造器<clinit>()方法与类的构造函数不同,它不需要显式调用父类构造,虚拟机会保证在子类<clinit>()方法执行之前,父类的<clinit>()方法已经执行完毕。因此在虚拟机中的第一个执行的<clinit>()方法的类肯定是java.lang.Object。

(2)由于父类的<clinit>()方法先执行,也就意味着父类中定义的静态语句块要优先于子类的变量赋值操作。

(3)<clinit>()方法不是必须的,如果一个类中没有静态语句,那么编译器可以不为这个类生成<clinit>()方法。

(4)接口中不能使用静态语句块,和类不同的是,执行接口的<clinit>()方法不需要先执行父接口的<clinit>()方法。只有当父接口中定义的变量被使用时,父接口才会被初始化。另外,接口的实现类在初始化时也一样不会执行接口的<clinit>()方法。

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

3. 类加载的三种方式

(1)由 new 关键字创建一个类的实例。

(2)调用 Class.forName() 方法,通过反射加载类。

(3)调用某个ClassLoader实例的loadClass()方法。

三者的区别汇总如下:

(1)方法1和2都是使用的当前类加载器。方法3是由用户指定的类加载器加载。

(2)方法1是静态加载,2、3是动态加载。

(3)对于两种动态加载,如果程序需要类被初始化,就必须使用Class.forName(name)的方式。

Class.forName(className);
//实际上是调用的是:
Class.forName(className, true, this.getClass().getClassLoader());//第二个参为true即默认类需要初始化,初始化会触发目标对象静态块的执行和静态变量的初始化
ClassLoader.loadClass(className);
//实际上调用的是:
ClassLoader.loadClass(name, false);//第二个参数即默认得到的class还没有进行链接,意味着不进行初始化等系列操作,即静态代码块不会执行

(转) JVM——Java类加载机制总结的更多相关文章

  1. JVM——Java类加载机制总结

    )解析:解析阶段是把虚拟机中常量池的符号引用替换为直接引用的过程. 2.3 初始化 类初始化时类加载的最后一步,前面除了加载阶段用户可以通过自定义类加载器参与以外,其余都是虚拟机主导和控制.到了初始化 ...

  2. jvm之java类加载机制和类加载器(ClassLoader),方法区结构,堆中实例对象结构的详解

    一.类加载或类初始化:当程序主动使用某个类时,如果该类还未被加载到内存中,则JVM会通过加载.连接.初始化3个步骤来对该类进行初始化.如果没有意外,JVM将会连续完成3个步骤. 二.类加载时机:  1 ...

  3. Java 类加载机制

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

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

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

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

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

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

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

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

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

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

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

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

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

随机推荐

  1. memcached程序端口监控脚本

    线上memcached服务器启动了很多实例,端口很多,需要对这些端口进行监控,并在端口关闭的情况下自启动.监控脚本如下: [root@memcache2 ~]# ps -ef|grep /usr/bi ...

  2. Centos下堡垒机Jumpserver V3.0环境部署完整记录(1)-安装篇

    由于来源身份不明.越权操作.密码泄露.数据被窃.违规操作等因素都可能会使运营的业务系统面临严重威胁,一旦发生事故,如果不能快速定位事故原因,运维人员往往就会背黑锅.几种常见的运维人员背黑锅场景:1)由 ...

  3. Redis数据"丢失"讨论及规避和解决的几点总结

    Redis大部分应用场景是纯缓存服务,请求后端有Primary Storage的组件,如MySQL,HBase;请求Redis的键未命中,会从primary Storage中获取数据返回,同时更新Re ...

  4. 个人作业Week2-代码复审(修改明确了要求)

    代码复审 零,说在前面的话 大家完成了个人项目之后,都写了很多代码. 这些代码可能: 大括号换行/不换行 使用tab缩进/使用空格缩进 变量名函数名的定义很好/不好 每个函数都有详细的注释解释函数的功 ...

  5. 20135337——Linux实践二:模块

    一.编译&生成&测试&删除 1.编写模块代码,查看如下 gedit 1.c(编写) cat 1.c(查看) MODULE_AUTHOR("Z") MODUL ...

  6. 软件工程实践作业2 --梭哈游戏(java) 实践报告

    一,题目简介: 1.创建一副扑克牌 7------k 加入到集合对象中2.对扑克牌洗牌3.定义参与游戏的玩家的人,通过键盘输入,限定人数2-54.人数符合要求继续执行,不符合退出5.对玩家发牌,每个人 ...

  7. SpringBoot-简单实例

    在进行实例之前,首先须确保电脑环境变量已经配置好,包括jdk.maven.此文章不做描述,不清楚自行百度. 第一步:来到springboot官网(https://start.spring.io/)下载 ...

  8. 在XShell中使用sz和rz命令下载和上传文件

    借助XShell,使用linux命令sz可以很方便的将服务器上的文件下载到本地,使用rz命令则是把本地文件上传到服务器 工具/原料   XShell CentOS 6.5 使用sz下载文件   1 输 ...

  9. Linux MYSQL:dead but pid file exists

    MYSQL dead but pid file exists问题 - CSDN博客https://blog.csdn.net/shilian_h/article/details/38020567 Er ...

  10. CentOS7 截图

    https://blog.csdn.net/downing114/article/details/51433862 https://blog.csdn.net/lotluck/article/deta ...