类加载器分析(高新技术)

来源:互联网 发布:java猜拳游戏代码 编辑:程序博客网 时间:2024/06/07 07:09

类加载器分析


一、类加载器

1、什么是类加载器?

    加载类的工具,当程序需要的某个类,那么需要通过类加载器把类的二进制加载到内存中,类加载器也是Java类

2、类的加载过程

当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实现对这个类进行初始化。
加载: 
就是指将class文件读入内存,并为之创建一个Class对象。任何类被使用时系统都会建立一个Class对象。
连接:
验证 是否有正确的内部结构,并和其他类协调一致
准备 负责为类的静态成员分配内存,并设置默认初始化值
解析 将类的二进制数据中的符号引用替换为直接引用
初始化: 这里就不细说了。。。


3、类初始化时机

创建的时机有下面6种情况
a.创建类的实例
b.访问类的静态变量,或者为静态变量赋值
c.调用类的静态方法
d.使用反射方式来强制创建某个类或接口对应的java.lang.Class对象
e.初始化某个类的子类
f.直接使用java.exe命令来运行某个主类

4、java.lang.ClassLoader类介绍

java.lang.ClassLoader类的基本职责就是根据一个指定的类的名称,找到或者生成其对应的字节代码,然后从这些字节代码中定义出一个 Java 类,即 java.lang.Class类的一个实例。

ClassLoader提供了一系列的方法,比较重要的方法如:



5、类加载器的树状组织结构

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

5.1、系统提供的类加载器

系统提供的类加载器主要有下面三个:
引导类加载器(bootstrap class loader):它用来加载 Java 的核心库,比如System,String等,是用原生代码(C++)来实现的,并不继承自java.lang.ClassLoader
扩展类加载器(extensions class loader):它用来加载 Java 的扩展库。Java 虚拟机的实现会提供一个扩展库目录。该类加载器在此目录里面查找并加载 Java 类。
系统类加载器(system class loader):它根据 Java 应用的类路径(CLASSPATH)来加载 Java 类。一般来说,Java 应用的类都是由它来完成加载的。 可以通ClassLoader.getSystemClassLoader()来获取它。

5.2、Java 应用开发人员编写的类加载器

属于应用程序根据自身需要自定义的ClassLoader,如tomcat、jboss都会根据j2ee规范自行实现ClassLoader
加载过程中会先检查类是否被已加载,检查顺序是自底向上,从Custom ClassLoader到BootStrap ClassLoader逐层检查,只要某个classloader已加载就视为已加载此类,保证此类只所有ClassLoader加载一次。而加载的顺序是自顶向下,也就是由上层来逐层尝试加载此类。除了引导类加载器之外,所有的类加载器都有一个父类加载器。通过 上面表中给出的 getParent()方法可以得到。对于系统提供的类加载器来说,系统类加载器的父类加载器是扩展类加载器,而扩展类加载器的父类加载器是引导类加载器;对于开发人员编写的类加载器来说,其父类加载器是加载此类加载器 Java 类的类加载器。因为类加载器 Java 类如同其它的 Java 类一样,也是要由类加载器来加载的。一般来说,开发人员编写的类加载器的父类加载器是系统类加载器。类加载器通过这种方式组织起来,形成树状结构。树的根节点就是引导类加载器。
下图中给出了一个典型的类加载器树状组织结构示意图。



5.3、演示类加载器的树状组织结构

package cn.wangjing_10;public class ClassLoaderTree {public static void main(String[] args) {ClassLoader loader = ClassLoaderTree.class.getClassLoader();while (loader != null) {System.out.println(loader.toString());loader = loader.getParent();}}}

程序输出结果是:
sun.misc.Launcher$AppClassLoader@1c0ec97
sun.misc.Launcher$ExtClassLoader@ecb281


6、类加载器的委托机制:

        1>当Java虚拟机要加载一个类时,到底派出哪个类加载器去加载呢?
①首先当前线程的类加载器去加载线程中的第一个类.
②如果类A中引用了类B,Java虚拟机将使用加载类A的类加载器加载类B
③还可以直接调用ClassLoader.loadClass()方法来指定某个类加载器去加载某个类.
        2>每个类加载器加载类时,又先委托给其上级类加载器.
            ①当所有祖宗类加载器没有加载到类,回到发起者类加载器,如果还加载不了,则抛出ClassNotFoundException异常,它不会 去找发起者类加载器的儿子,因为没有getChild()方法,即使有,有那么多的儿子交给那一个呢?所以干错就不叫给儿子处理了.委托机制有什么好处?集中管理,如果我们写了几个类加载器,都去加载某个类,那么内存中就有多份这个类的字节码。 能不能自己写一个类叫java.lang.System?为了不让我们写System类,类加载采用委托机制,这样可以保证爸爸优先,也就是使用的永远是爸爸的(系统的)System类,而不是我们写的System类.

7、自定义类加载器演示

public class People {public void say(){        System.out.println("hello world!");    }}

class MyClassLoader extends ClassLoader {    //类加载器的名称    private String name;    //类存放的路径    private String path = "C:\\eclipse_workplace1\\File\\src\\cn\\wangjing_10\\";     MyClassLoader(String name) {        this.name = name;    }         MyClassLoader(ClassLoader parent, String name) {        super(parent);        this.name = name;    }    /**     * 重写findClass方法     */    @Override    public Class<?> findClass(String name) {        byte[] data = loadClassData(name);        return this.defineClass(name, data, 0, data.length);    }    public byte[] loadClassData(String name) {        try {            name = name.replace(".", "//");            FileInputStream is = new FileInputStream(new File(path + name + ".class"));            ByteArrayOutputStream baos = new ByteArrayOutputStream();            int b = 0;            while ((b = is.read()) != -1) {                baos.write(b);            }            return baos.toByteArray();        } catch (Exception e) {            e.printStackTrace();        }        return null;    }}

public class ClassLoaderTest {     public static void main(String[] args) throws InstantiationException, IllegalAccessException, ClassNotFoundException {        //新建一个类加载器        MyClassLoader cl = new MyClassLoader("myClassLoader");        //加载类,得到Class对象        Class<?> clazz = cl.loadClass("classloader.Animal");        //得到类的实例        People people=(People) clazz.newInstance();        people.say();    } }




0 0
原创粉丝点击