JVM——Java类加载机制总结
1. 类加载器的组织结构
转载请注明出处:http://blog.csdn.net/seu_calvin/article/details/52301541
类加载器 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)来完成,也可以由用户自定义的类加载器完成,开发人员可以通过定义类加载器去控制字节流的获取方式。
(1)通过类的全名产生对应类的二进制数据流(注意,若未找到该类文件,只有在类实际使用时才抛出错误)。
(2)分析并将这些二进制数据流转换为方法区的运行时数据结构。
(3)创建代表这个类的java.lang.Class对象。作为方法区这些数据的访问入口。
2.2 链接阶段(实现 Java 的动态性的重要一步)
(1)验证:主要的目的是确保class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身安全。验证点可能包括:class文件格式规范、这个类是否继承了不允许被继承的类(被final修饰的)、如果这个类的父类是抽象类,是否实现了起父类或接口中要求实现的所有方法、不能把一个父类对象赋值给子类数据类型、方法的访问性(private、protected、public、default)是否可被当前类访问等等。
(2)准备:准备阶段为类的成员变量分配内存空间并设置类变量初始值的阶段,这些变量所使用的内存都在方法区中分配。所有原始类型的值都为0。如float为0f、 int为0、boolean为0、引用类型为null。
(3)解析:解析阶段是把虚拟机中常量池的符号引用替换为直接引用的过程。
2.3 初始化
类初始化时类加载的最后一步,前面除了加载阶段用户可以通过自定义类加载器参与以外,其余都是虚拟机主导和控制。到了初始化阶段,才是真正执行类中定义Java程序代码。初始化阶段,根据程序中的定制,初始化类变量。
初始化过程其实是执行类构造器方法的过程。
(类构造器方法是由编译器自动收集类中所有类变量的赋值动作和静态语句块中的语句合并产生的。)
//静态语句块中只能访问定义在静态语句块之前的变量,定义在它之后的变量可以赋值,但不能访问
public class Test{
static{
i=0;//給变量赋值,可以通过编译
System.out.print(i);//这句编译器会提示非法向前引用
}
static int i=1;
}
初始化过程会被触发执行的条件汇总:
(1)使用new关键字实例化对象、读取或设置一个类的静态字段(被final修饰、已在编译器把结果放入常量池的静态字段除外)的时候,以及调用类的静态方法的时候。
(2)对类进行反射调用的时候。
(3)当初始化一个类的时候,如果发现其父类还没有进行过初始化,则进行父类的初始化。
(4)JVM启动时,用户指定执行的主类(包含main方法所在类),虚拟机会先初始化这个类。
【关于构造器方法拓展知识】(可以不看)
(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都是使用的当前类加载器(this.getClass.getClassLoader)。方法3由用户指定类加载器并且加载的类与当前类分属不同的命名空间。
(2)方法1是静态加载,2、3是动态加载。
(3)对于两种动态加载,区别如下。
Class.forName(className);
//实际上是调用的是:
Class.forName(className, true, this.getClass().getClassLoader());//第二个参数设置Class被loading后是不是必须被初始化,默认初始化
ClassLoader.loadClass(className);
//实际上调用的是:
ClassLoader.loadClass(name, false);//第二个参数指Class是否被链接,默认为false
通过上面的描述,如果程序依赖于Class是否被初始化,就必须用Class.forName(name)了。
JVM——Java类加载机制总结的更多相关文章
- (转) JVM——Java类加载机制总结
背景:对java类的加载机制,一直都是模糊的理解,这篇文章看下来清晰易懂. 转载:http://blog.csdn.net/seu_calvin/article/details/52301541 1. ...
- jvm之java类加载机制和类加载器(ClassLoader),方法区结构,堆中实例对象结构的详解
一.类加载或类初始化:当程序主动使用某个类时,如果该类还未被加载到内存中,则JVM会通过加载.连接.初始化3个步骤来对该类进行初始化.如果没有意外,JVM将会连续完成3个步骤. 二.类加载时机: 1 ...
- Java 类加载机制
类的加载: 类的初始化: 类什么时候才被初始化:1)创建类的实例,也就是new一个对象2)访问某个类或接口的静态变量,或者对该静态变量赋值3)调用类的静态方法4)反射(Class.forName(&q ...
- Java类加载机制深度分析
转自:http://my.oschina.net/xianggao/blog/70826 参考:http://www.ibm.com/developerworks/cn/java/j-lo-class ...
- 理解Java类加载机制(译文)
理解java类加载机制 你想写类加载器?或者你遇到了ClassCastException异常,或者你遇到了奇怪的LinkageError状态约束异常.应该仔细看看java类的加载处理了. 什么是类加载 ...
- 剑指Offer——知识点储备-故障检测、性能调优与Java类加载机制
剑指Offer--知识点储备-故障检测.性能调优与Java类加载机制 故障检测.性能调优 用什么工具可以查出内存泄露 (1)MerroyAnalyzer:一个功能丰富的java堆转储文件分析工具,可以 ...
- 两道面试题,带你解析Java类加载机制
文章首发于[博客园-陈树义],点击跳转到原文<两道面试题,带你解析Java类加载机制> 在许多Java面试中,我们经常会看到关于Java类加载机制的考察,例如下面这道题: class Gr ...
- 【转】两道面试题,带你解析Java类加载机制(类初始化方法 和 对象初始化方法)
本文转自 https://www.cnblogs.com/chanshuyi/p/the_java_class_load_mechamism.html 关键语句 我们只知道有一个构造方法,但实际上Ja ...
- Java类加载机制及自定义加载器
转载:https://www.cnblogs.com/gdpuzxs/p/7044963.html Java类加载机制及自定义加载器 一:ClassLoader类加载器,主要的作用是将class文件加 ...
随机推荐
- iOS开发ReactiveCocoa学习笔记(四)
ReactiveCocoa常见操作方法介绍: demo地址:https://github.com/SummerHH/ReactiveCocoa.git 1.1 ReactiveCocoa操作须知 所有 ...
- 使用compiz出现奔溃的一些应急办法
Linux Mint 17.1 CompizConfig is also installed by default so you can configure every aspect of Compi ...
- 内置函数isNaN()
NaN(not a number)的产生:算术运算返回一个未定义的或无法表示的值 1.NaN并不一定用于表示某些值超出表示范围的情况.将某些不能强制转换为数值的非数值转换为数值的时候,也会得到NaN. ...
- 一些C/C++中的函数
项目中使用到的C/C++中的一些函数,记录下来加以理解和掌握. 1.memset( ) memset是计算机中C/C++语言函数.将s所指向的某一块内存中的前n个 字节的内容全部设置为ch指定的ASC ...
- 配置海康IPC或大华IPC通过路由器公网访问
设备:路由器DLink-DIR-600M,海康IPC:DS-2CD864FWD-E 海康默认端口为8000,HTTP访问为80,RTSP访问端口为554. 配置分成两步,分别为配置IPC相关网络参数和 ...
- MySQL-数据类型及选择
一.数据类型 详见:http://www.runoob.com/mysql/mysql-data-types.html 二.类型选择 整形>date,time>enum,char>v ...
- ajax请求成功后js刷新当前页,当前页是post查询结果(用post请求进行搜索筛选)的问题
下面的一个ajax操作,原先操作成功会刷新当前页,保证用户看到的数据是最新的,一般情况不会出现问题.$.ajax({ url: url + "/addTeacherAuth", / ...
- Api容器在应用架构演化中的用途
单层架构 在最开始编程的时候相信大家都写过下面这种架构,界面代码,业务代码,数据库连接全部在工程面完成.当然这种架构在处理很小的程序的时候依然有生命力 两层架构 后来我们发现数据访问的代码大量重复,应 ...
- MySQL binlog server
从5.6版本开始,可以利用 mysqlbinlog命令把远程机器的日志备份到本地目录,这样就更加方便快捷的实现一个binlog server. 环境介绍:192.168.56.100是备份服务器,19 ...
- java实现单链表归并算法
public class LinkMergeSort {static int number=0;public static void main(String[] args) {int[] a = {1 ...