Java类加载器学习1——类加载器的基本概念

 

一、程序使用java类的运行顺序

 

当程序主动使用某个类的时候,若该类还未被加载至内存中,系统会通过加载,连接,初始化三个步骤对类进行初始化,有事也把这三个步骤称为类加载或者类的初始化。

 

1 类的加载

将被编译的.java而成为.class字节码读入JVM内存并为之创建一个java.lang.Class对象,也就是说当程序中使用任何类的时候系统都会为之建立一个java.lang.Class对象。类的加载由类加载器完成,类加载器通常有JVM提供,我们称JVM提供的类加载器为系统类加载器。当然实际的情况可能更加复杂比如Java字节代码可能是通过工具动态生成的,也可能是通过网络下载的。

 

2 类的连接

当生成一个对应的.class对象后,接着会进入连接阶段,会将类的二进制数据合并到JRE中,该阶段又认为验证,准备,解析三个阶段。

 

3 类的初始化

由JVM负责对类进行初始化,主要就是对静态属性进行初始化。(1)声明静态属性时指定初始值 (2)使用静态初始化块为静态属性指定初始值。

 

本文主要讲解第一个步骤——类的加载。

 

 

二、类的加载的基本概念

基本上所有的类加载器都是java.lang.ClassLoader类的一个实例。java.lang.ClassLoader类的基本职责就是根据一个指定的类的名称,找到或者生成其对应的字节代码,然后从这些字节代码中定义出一个Java类,即java.lang.Class类的一个实例。除此之外ClassLoader还负责加载Java应用所需的资源,如图像文件和配置文件等。不过本文只讨论其加载类的功能。为了完成加载类的这个职责,ClassLoader提供了一系列的方法。JDK中几个比较重要的方法:

getParent()
返回委托的父类加载器

loadClass(String name)
加载名称为name的类,返回的结果是java.lang.Class类的实例

findClass(String name)
查找名称为name的类,返回的结果是java.lang.Class类的实例

findLoadedClass(String name)
查找名称为 name的已经被加载过的类,返回的结果是 java.lang.Class类的实例

defineClass(String name, byte[] b, int off, int len)
把字节数组b中的内容转换成Java类,返回的结果是java.lang.Class类的实例。此方法被声明为final

resolveClass(Class<?> c)
链接指定的Java类 

上述name是二进制名,按照《Java Language Specification》的定义,任何作为String类型参数传递给ClassLoader中方法的类名称都必须是一个二进制名称。 有效类名称的示例包括:

"java.lang.String"
"javax.swing.JSpinner$DefaultEditor"
"java.security.KeyStore$Builder$FileBuilder$1"
"java.net.URLClassLoader$3$1"

 

 

 

三、类加载器的分类

Java 中的类加载器大致可以分成两类,一类是系统(JVM)提供的,一类是由Java应用开发人员编写的。

 

系统提供的类加载器主要有下面三个:

引导类加载器(bootstrap class loader)
用来加载 Java 的核心库,是用原生代码(C++)来实现的,并不继承自java.lang.ClassLoader。

扩展类加载器(extensions class loader)
用来加载Java的扩展库。Java虚拟机的实现会提供一个扩展库目录。该类加载器在此目录里面查找并加载 Java 类。

系统类加载器(system class loader)
根据Java应用的类路径(CLASSPATH)来加载Java类。一般来说Java应用的类都是由它来完成加载的。可以通过 ClassLoader.getSystemClassLoader()来获取它。

 

除了系统提供的类加载器外开发人员可以通过继承java.lang.ClassLoader类的方式实现自己的类加载器,以满足一些特殊的需求。

 

除了引导类加载器外,所有的类加载器都有一个父类加载器。通过getParent()方法可以得到。对于系统提供的类加载器来说,系统类加载器的父类加载器是扩展类加载器,而扩展类加载器的父类加载器是引导类加载器;对于开发人员编写的类加载器来说,其父类加载器是加载此类加载器Java类的类加载器。因为类加载器Java类如同其它的Java类一样,也要由类加载器来加载的。一般来说开发人员编写的类加载器的父类加载器是系统类加载器。类加载器通过这种方式组织起来,形成树状结构。树的根节点就是引导类加载器。看一张传智播客的图

 

 

看一段测试代码 

public class Test
{

 public static void main(String[] args)
 {

  // sun.misc.Launcher$AppClassLoader
  System.out.println(Test.class.getClassLoader().getClass().getName());

  // null
  // 类加载器本身也是java类,也需要被加载,但是第一个加载器如果是java类的话,被谁来加载呢?
  // 答案BootStrap是第一个类加载器,是C++代码写成的二进制代码,这里通过java获取不了
  System.out.println(System.class.getClassLoader());

  // sun.misc.Launcher$AppClassLoader——>sun.misc.Launcher$ExtClassLoader——>null
  ClassLoader loader = Test.class.getClassLoader();
  while (null != loader)
  {
   System.out.println(loader.getClass().getName());
   loader = loader.getParent();
  }
  System.out.println(loader);
 }

}

 

四、类加载器的父类委托机制

Java的类加载器自从JDK1.2开始便引入了一条机制,叫做父类委托机制。

一个类需要被加载的时候,JVM先会调用他的父类加载器进行加载。如果父类加载器加载不了,再使用其子类进行加载。当然这类所说的父类加载器,不一定他们之间是继承的关系,有可能仅仅是包装的关系。不能片面理解。

当Java虚拟机要加载类时,如果上一级加载器可以加载则交由上一级加载,如用户编写一个java.lang.System类,交给AppClassLoader加载—>ExtClassLoader加载—>BootStrap加载,而rt.jar这个包中本来就有一个System类,所以用户编写的System类不起作用。如果BootStrap加载不到,则将由ExtClassLoader加载—>AppClassLoader加载,最后还加载不了就返回ClassNotFoundException异常,不会交给发起请求的加载器的子加载器。

 

Java之所以出现这条机制,因为是处于安全性考虑。害怕用户自己定义class文件然后自己写一个类加载器来加载原本应该是JVM自己加载的类。这样会是JVM虚拟机混乱或者说会影响到用户的安全。

 

参考地址

http://www.ibm.com/developerworks/cn/java/j-lo-classloader/index.html#major5

http://blog.csdn.net/a352193394/article/details/7343385

 

 

时间: 2024-08-01 06:05:50

Java类加载器学习1——类加载器的基本概念的相关文章

java jvm 类加载器-java中为什么要自定义类加载器

问题描述 java中为什么要自定义类加载器 java为什么要自定义类加载器 面试题 希望大神尽快解答 急用 谢谢了! 解决方案 http://www.iteye.com/topic/240013http://blog.sina.com.cn/s/blog_a1ebbd3501019equ.html 解决方案二: 一.类加载器类别? ?* ?1.java虚拟机自带的加载器? ?* ??根类加载器(Bootstrap,c++实现)? ?* ? ?扩展类加载器(Extension,java实现)? ?

深入解析Java中的Class Loader类加载器_java

类加载的过程类加载器的主要工作就是把类文件加载到JVM中.如下图所示,其过程分为三步: 1.加载:定位要加载的类文件,并将其字节流装载到JVM中: 2.链接:给要加载的类分配最基本的内存结构保存其信息,比如属性,方法以及引用的类.在该阶段,该类还处于不可用状态: (1)验证:对加载的字节流进行验证,比如格式上的,安全方面的: (2)内存分配:为该类准备内存空间来表示其属性,方法以及引用的类: (3)解析:加载该类所引用的其它类,比如父类,实现的接口等. 3.初始化:对类变量进行赋值. 类加载器的

深入学习虚拟机类加载过程

JVM的类加载机制是指虚拟机 把描述类的数据从class文件加载到内存,并对数据进行校验,转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型的实现过程. 类加载过程具体可以分成下面几个步骤: (1)装载:查找和导入Class文件: (2)链接:把类的二进制数据合并到JRE中:  校验:检查载入Class文件数据的正确性:  准备:给类的静态变量分配存储空间,赋默认值:  解析:将符号引用转成直接引用: (3)初始化:对类的静态变量,静态代码块执行初始化操作. 加载 Loading过程

Java Reflection(十二):动态类加载与重载

原文地址作者: Jakob Jenkov 译者:叶文海(yewenhai@gmail.com) 内容索引类加载器类加载体系类加载动态类加载动态类重载自定义类重载类加载/重载示例 Java允许你在运行期动态加载和重载类,但是这个功能并没有像人们希望的那么简单直接.这篇文章将阐述在Java中如何加载以及重载类. 你可能会质疑为什么Java动态类加载特性是Java反射机制的一部分而不是Java核心平台的一部分.不管怎样,这篇文章被放到了Java反射系列里面而且也没有更好的系列来包含它了. 类加载器 所

java中HotSpot算法及垃圾收集器简介

垃圾回收算法基本思想: 1.枚举根节点(GC Roots) 在垃圾回收时,我们要想办法找出哪些对象是存活的,一般会选取一些被称为GC Root的对象,从这些对象开始枚举.枚举时要求所有对象停下来,也就是大家所称的"Stop the world".所有的算法实现都会将虚拟机停下来的,否则分析结果的准确性将无法保证.当执行系统停顿下来之后,虚拟机不需要遍历所有的根节点和上下文去确定GC Roots,而是存在着一个OopMap的数据结构来达到这个目的.在类加载完成的时候,虚拟机就会把什么类的

listview-大四安卓学习mars播放器Listview的问题

问题描述 大四安卓学习mars播放器Listview的问题 抱歉麻烦各位了,本人大四狗,目前在看安卓开发,学习mars老师的音乐播放器时遇到了 个问题,就是设置了SimpleAdapter之后仍然无法显示歌名的内容,只显示了个空白的 TEXTVIEW,我研究了无数次依旧没有发现问题在哪,因此来求教各位大神 附上全部代码,没有错误信息,就是显示不出来,每一步调试过确定都有值 代码如下 package com.example.android_mp3; import java.io.StringRea

Python装饰器学习

在<Core Python Programming 2nd>中学习到了装饰器,这对我来说是个完全陌生的语法,第一遍愣是没看懂,很有必要记一下.   第一眼看到这个词Decorator,我联想到了DP中的Decorator模式,后来才知道完全不是这么一回事.(再次鄙视一下国内浮躁的博客,我google了一下,几乎千篇一律都是什么锁同步装饰器.超时装饰器,我对原作者表达敬仰,可是大家都是转载就不像话了,也是对网络资源的极大浪费,也许真正有价值的博文就湮没在这片都是一模一样的东西里了)   1. 这

Java实现Web版RSS阅读器(五)初步完成阅读功能

上一篇博文<Web版RSS阅读器(四)--定制自己的Rss解析库myrsslib4j>中,已经分享给大家制作自己的rss解析库.稍微有点遗憾的是,它仅仅支持rss格式的博客.现在给大家分享一下我基于rome修改而成的另一款rss解析库--myrome,完美支持atom和rss 2种格式. myrome.jar是在rome的基础上修改而来的,主要改动的地方是:(查看详细修改说明) 修改GetAuthor()返回null 修改getPublishedDate()返回null 添加获取文章摘要的接口

Java实现Web版RSS阅读器(四)定制自己的Rss解析库myrsslib4j

在上篇博文<Web版RSS阅读器(三)--解析在线Rss订阅>中,已经提到了遇到的问题,这里再详细说一下. 在解析rss格式的订阅时,遇到的最主要的问题是,出现了"Server returned HTTP response code: 403 for URL: http://xxxxxx"的错误,百度一下就知道,这是在网站访问中很常见的一个错误,服务器理解客户的请求,但拒绝处理它.即拒绝访问!接着查资料,得知某些服务器(比如CSDN博客)拒绝java作为客户端进行对其的访问