Reference:

[1] http://www.cnblogs.com/kevin2chen/p/6714214.html

当调用 java命令运行一个java程序时,会启动一个java虚拟机进程。同一个jvm的所有线程、所有变量都处于同一个进程里,都使用该jvm进程的内存区。 jvm进程终止,jvm内存中的数据将全部丢失。

jvm进程终止的情况:

1.程序运行到最后正常结束。

2.遇到System.exit()或Runtime.getRuntime.exit()。

3.遇到未捕获的异常或错误

4.程序所在的平台强制结束了JVM进程

类的加载

当程序主动使用某个类时,如果该类还未被加载到内存中,系统会进行类加载。类加载指的是将类的class文件读入内存,并为之创建一个java.lang.Class的实例。因为java中万物皆为对象,类也是java.lang.Class类型的对象。

类加载具体有加载、连接和初始化3个步骤,加载阶段需要完成的事情有:

  1)通过一个类的全限定名来获取定义此类的二进制字节流。

  2)将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。

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

类的加载,是由类加载器来完成的,类加载器通常由JVM提供。通过使用不同的类加载器,可以加载以下不同来源的类的二进制数据:

  1.从本地文件系统加载class文件

  2.从jar包中直接加载class文件

  3.通过网络加载class文件

  4.把一个java源文件动态编译并加载

类的连接

负责把类的二进制数据合并到JRE(java运行环境)中

  1.验证:检测被加载的类是否有正确的内部结构,是否被破坏或包含不良代码,并和其他类协调一致

  2.准备:负责为类的静态属性分配内存,并设置默认初始值

  3.解析:将类的二进制数据中的符号引用替换成直接引用

类初始化

主要对类的静态属性进行初始化。可以在声明静态属性时指定初始值和通过静态初始化块指定初始值,JVM会按照这些语句在程序中的顺序依次执行。

类加载器

每个类加载器(除了根类加载器)都是java.lang.ClassLoader的实例,负责将.class文件加载到内存中,并为之生成对应的java.lang.Class对象。

同一个.class不会被同一个类加载器加载两次,如何判断是同一个类: java中,一个类用其全限定类名标识--包名+类名;jvm中,一个类用其全限定类名+其类加载器标识---包名+类名+类加载器名

加载器层次结构:

JVM启动时,会形成由三个类加载器组成的初始类加载器层次结构:

1.Bootstrap ClassLoader 根类加载器(引导类加载器),加载java的核心类(限定的加载路径:jdk1.8_02/jre/lib/rt.jar)。它不是java.lang.ClassLoader的子类,而是由JVM自身实现的。虚拟机为了安全性以及功能的完整性,并不是任何存在于启动类加载器路径下的jar都会被加载,只有可信类(trusted classes )会被加载,所以开发者不要将自定义的类放在此目录。

2.Extension ClassLoader 扩展类加载器,加载JRE的扩展目录中JAR的类包(限定的加载路径:%JAVA_HOME%/jre/lib/ext/或java.ext.dirs系统属性指定的目录)

3.System ClassLoader 系统类加载器,加载java.class.path系统属性或CLASSPATH环境变量所指定的jar包和类路径,可通过ClassLoader的静态方法ClassLoader.getSystemClassLoader()获取系统类加载器。如果没有特别指定,用户自定义的类加载器以该类加载器作为它的父加载器。也可以通过Class实例的getClassLoader()方法当前类的类加载器。

4.自定义类加载器

JVM系统自带的类加载器在程序运行中只能加载对应路径的.class文件,无法改变其搜索路径。如果想在运行时从其他路径加载类,就要编写自定义的类加载器。

类加载的机制

1.全盘负责:某类所依赖及其引用的所有类,都由同一个加载器负责加载,除非显示使用另外一个加载器。

2.双亲委托: 当一个类加载器收到类加载的请求,首先将请求委派给父类加载器,递归到Bootstrap ClassLoader。然后加载器根据请求尝试搜索和加载类,若无法加载该类时则向子类加载器反馈信息(抛出ClassNotFoundException),由子类加载器自己去加载。

类加载期之间的父子关系并不是类继承上的父子关系,是采用组合的方式实现双亲委派模型的。

根类加载器是由c++实现的,不是由java语言实现,没有继承ClassLoader,所以扩展类加载器调用parent()返回的是null。但扩展类加载器实际上仍可以委派给根类加载器。

使用双亲委托模式的原因:被父类加载器加了的类可以避免避免被子类重新加载,因为在JVM中由全限定名+类加载器名标识类。另外可以避免加载到同sun公司核心API同名的恶意类。

自定义类加载器

JVM中除了根加载器之外,所有类加载器都是ClassLoader子类的实例,开发者通过扩展ClassLoader并重写ClassLoader所包含的方法来实现自定义的类加载器。

如上源码所示,loadClass()方法内部主要是双亲委派模型的实现,在最后调用findClass()方法加载类,所以自定义类加载器重写findClass()比重写loadClass()方便,可以避免覆盖默认类加载器的父类委托和缓冲机制两种策略。

ClassLoader类的核心方法:

  1. protected synchronized Class<?> loadClass(String name, boolean resolve)根据指定的binary name(由两个不同部分组成的名字,即全限定类名)来加载类,返回Class对象。

  2. protected Class<?> findClass(String name)根据二进制名称来查找类,返回Class对象。此方法应该被自定义类加载器的实现重写,在通过父类加载器检查所请求的类后,被loadClass方法调用。

  3. final defineClass(String name,byte[] b,int off,int len)将指定类的字节码文件读入字节数组内,并把它转为Class实例,该字节码文件可以来源于网络或本地。

  4. findLoadedClass(String name)返回jvm装载的name类的Class实例,若无返回null。

  5. static getSystemClassLoader()返回系统类加载器。

  6. findSystemClass(String name)从本地文件系统加载class文件,并生成Class对象。

使用自定义类加载器可以实现如下功能:

  执行代码前自动验证数字签名;

  根据用户提供的密码解密代码,从而可以实现代码混淆器来避免反编译class文件;

  根据用户需求来动态的加载类;

  根据应用需求把其他数据以字节码的形式加载到应用中;

URLClassLoader 类

java 为ClassLoader提供了一个实现类URLClassLoader ,该类也是系统类加载器和扩展类加载器的父类,它可以从本地文件系统和远程主机获取二进制文件来加载类。

URLClassLoader的两个构造器

  URLClassLoader(URL[] urls):使用默认的父类加载器创建一个ClassLoader对象,该对象将从urls所指定的系列路径来查询并加载类。

  URLClassLoader(URL[] urls, ClassLoader parent):使用指定的父类加载器创建。。。

一旦获得URLClassLoader对象后,就可以调用类加载器的 loadClass()方法来加载指定的类。

加载图片、视频、文本等非类资源

ClassLoader除了用于加载类外,还可以用于加载图片、视频等非类资源,也是采用双亲委派模型将加载资源的请求传递到顶层的Bootstrap ClassLoader,在其对应的目录下搜索资源,若失败才逐层返回并搜索。

相关的实例方法:

  URL getResource(String name):资源名称name是以 '/' 分隔的标识资源的路径名称,返回资源的 URL 对象的枚举。

  InputStream getResourceAsStream(String name):返回读取指定资源的输入流。

  Enumeration<URL> getResources(String name)

1)class.getResource(String path):返回URL对象

  path以'/'开头时,'/'表示ClassPath,从项目的classpath下查询资源;

  path不以'/'开头时,是从此类所在的包下查询资源;

步骤:先递归在所有parent classLoader的classpath里查找resource,如果未找到,则在JVM内置的calss loader的路径中查找。

2)class.getClassLoader().getResource(String name):返回URL对象

The name of a resource is a '/'-separated path name that identifies the resource.

name不能以'/'开头,指资源标识符(即相对于classpath的路径)。一般web项目的classpath路径为……/webapps/appName/WEB-INF/classes/。如果资源不在此目录下,需要用使用相对路径做调整。

String path= MyService.class.getClassLoader().getResource("config.properties").getPath();
Properties prop = new Properties();
prop.load(new FileReader(path));

Java Class Loader的更多相关文章

  1. Java Class Loader Retrospect

  2. Java: some learning note for Java calssloader and Servlet

    1. Java Classloader 链接: https://en.wikipedia.org/wiki/Java_Classloader 摘要: The Java Classloader is a ...

  3. java 运行指定类的main函数

    运行jar文件的方法是: java -jar xxx.jar 但是有时,我们希望运行里面的具体某个类,这时可以通过: java -cp xxx.jar xxx.com.xxxx  它会找到这个类的ma ...

  4. Tomcat从零开始(十)Loader

    第十课: 不知不觉就10篇blog了,说实话,我是第一次更这么长时间的Blog. 嗯,今天说说Loader,在以前的课程中,也就是内个能使用最初级的servlet的那一节,我们使用了URLClassL ...

  5. Java 9 揭秘(8. JDK 9重大改变)

    Tips 做一个终身学习的人. 在本章,主要介绍以下内容: 新的JDK版本控制方案是什么 如何使用Runtime.Version类解析JDK版本字符串 JDK JRE 9的新目录布局是什么 JDK 9 ...

  6. 详解Java内存区域?虚拟机类加载机制?

    一.Java运行时数据区域 1.程序计数器 “线程私有”的内存,是一个较小的内存空间,它可以看做当前线程所执行的字节码的行号指示器.Java虚拟机规范中唯一一个没有OutOfMemoryError情况 ...

  7. 探秘 Java 热部署三(Java agent agentmain)

    前言 让我们继续探秘 Java 热部署.在前文 探秘 Java 热部署二(Java agent premain)中,我们介绍了 Java agent premain.通过在main方法之前通过类似 A ...

  8. 探秘 Java 热部署

    # 前言 在之前的 深入浅出 JVM ClassLoader 一文中,我们说可以通过修改默认的类加载器实现热部署,但在 Java 开发领域,热部署一直是一个难以解决的问题,目前的 Java 虚拟机只能 ...

  9. 探秘 Java 热部署二(Java agent premain)

    # 前言 在前文 探秘 Java 热部署 中,我们通过在死循环中重复加载 ClassLoader 和 Class 文件实现了热部署的功能,但我们也指出了缺点-----不够灵活.需要手动修改文件等操作. ...

随机推荐

  1. hdu 1757 A Simple Math Problem (构造矩阵解决递推式问题)

    题意:有一个递推式f(x) 当 x < 10    f(x) = x.当 x >= 10  f(x) = a0 * f(x-1) + a1 * f(x-2) + a2 * f(x-3) + ...

  2. 浩哥解析MyBatis源码(六)——DataSource数据源模块之池型数据源

    原创作品,可以转载,但是请标注出处地址:http://www.cnblogs.com/V1haoge/p/6675674.html 1 回顾 上一文中解读了MyBatis中非池型数据源的源码,非池型也 ...

  3. "!function",自执行函数表达式

    如题为自执行函数表达式.在这种情况下,解析器在解析function关键字的时候,会将相应的代码解析成function表达式,而不是function声明.下面2个括弧()都会立即执行 (function ...

  4. 简聊iOS支付集成(支付宝和微信支付)

    一.支付集成是什么 1.现在大部分app都有快捷支付功能,支付集成将第三方支付平台集成到自己的项目中,能够完成自己项目中的支付功能, 二.支付集成的使用 <1>.支付宝: 下载SDK和De ...

  5. [Python]peewee使用经验

    peewee 使用经验 本文使用案例是基于 python2.7 实现 以下内容均为个人使用 peewee 的经验和遇到的坑,不会涉及过多的基本操作.所以,没有使用过 peewee,可以先阅读文档 正确 ...

  6. 学习Sass之安装篇

    Sass是基于ruby开发的,所以想要用Sass要先搭建ruby环境 1 Mac下安装 2 windows下安装 3 下载koala,只需要下载这个软件,其余什么都不需要你安装

  7. require.js疑惑

    昨天小颖分享了一篇require.js入门 ,今天小颖发现了一个很郁闷的问题,希望大神们帮小颖解释下到底是什么原理才能出现以下的现象,其实小颖昨天也有问过园友里的一位帅锅,只是他解释的小颖没太明白.嘻 ...

  8. 【one day one linux】linux下的软件包管理工具

    Linux 下的软件包管理工具 linux下的软件安装可以通过两种方式,一种是直接使用自带的软件包管理工具安装,另外一种通过编译源码安装. 1.软件包的种类 Red Hat和Fedora:redhat ...

  9. MySQL最常用数值函数

    数值函数: 用来处理很多数值方面的运算,使用数值函数,可以免去很多繁杂的判断求值的过程,能够大大提高用户的工作效率. 1.ABS(x):返回 x 的绝对值 mysql> select abs(- ...

  10. CF CROC 2016 Intellectual Inquiry

    题目链接:http://codeforces.com/contest/655/problem/E 大意是Bessie只会英文字母表中的前k种字母,现在有一个长度为m+n的字母序列,Bessie已经知道 ...