您的位置:首页 > 编程语言 > Java开发

JAVA基础知识--类加载器

2013-08-06 21:02 113 查看
一. 类加载器

1.类加载器基础知识

类加载器的作用就是获取.class里面的内容等等

java虚拟机中的三个类加载器:BootStrap,ExtClassLoader,AppClassLoader

类加载器也是java类,因为其他是java类的类加载器本身也是要被类加载器加载的,只有BootStrap不是java类,它嵌套在java虚拟机的内核中。

2.类加载器之间的父子关系和管辖范围

3.类加载器的委托机制



package cn.itcast.text2;
import java.util.Date;
public class ClassLoadTest{
public static void main(String[] args) throws Exception{
System.out.println(
ClassLoadTest.class.getClassLoader().
getClass().getName());//为AppClassLoader
System.out.println(
System.class.getClassLoader());//为null
}
}


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

1、加载类的方式

当Java虚拟机要加载一个类时,到底要用哪个类加载器加载呢?

1)首先,当前线程的类加载器去加载线程中的第一个类。

2)若A引用类B(继承或者使用了B),Java虚拟机将使用加载类A的类加载器来加载类B。

3)还可直接调用ClassLoader的LoaderClass()方法,来制定某个类加载器去加载某个类。

2、加载器的委托机制:每个类加载器加载类时,又先委托给上级类加载器。

思考:每个类加载器加载类时,又先委托给其上级类加载器。
当所有祖宗类加载器没有加载到类,回到发起者类加载器,还加载不了,则抛ClassNotFoundException,不是再去找发起者类加载器的儿子,因为没有getChild方法,即使有,那有多个儿子,找哪一个呢?

对着类加载器的层次结构图和委托加载原理,解释先前将ClassLoaderTest输出成jre/lib/ext目录下的itcast.jar包中后,运行结果为ExtClassLoader的原因。

每个ClassLoader本身只能分别加载特定位置和目录中的类,但他们可以委托其他类的加载器去加载,这就是类加载器的委托模式,类加载器一级级委托到BootStrap类加载器,当BootStrap在指定目录中没有找到要加载的类时,无法加载当前所要加载的类,就会一级级返回子孙类加载器,进行真正的加载,每级都会先到自己相应指定的目录中去找,有没有当前的类;直到退回到最初的类装载器的发起者时,如果它自身还未找到,未完成类的加载,那就报告ClassNoFoundException的异常。

简单说,就是先由发起者将类一级级委托为BootStrap,从父级开始找,找到了直接返回,没找到再返回给其子级找,直到发起者,再没找到就报异常。

3、委托机制的优点:可以集中管理,不会产生多字节码重复的现象。

补充:面试题

可不可以自己写个类为:java.lang.System呢?

回答:第一、通常是不可以的,由于类加载器的委托机制,会先将System这个类一级级委托给最顶级的BootStrap,由于BootStrap在其指定的目录中加载的是rt.jar中的类,且其中有System这个类,那么就会直接加载自己目录中的,也就是Java已经定义好的System这个类,而不会加载自定义的这个System。

第二、但是还是有办法加载这个自定义的System类的,此时就不能交给上级加载了,需要用自定义的类加载器加载,这就需要有特殊的写法才能去加载这个自定义的System类的。

4.加载类的方式:

一、用当前线程的类加载器加载了线程中的第一个类,然后这个类引用到的其他类,那么那个类也用这个线程的这个类加载器进行加载。

二、可以直接调用ClassLoader.loadClass()方法来指定某个类加载器加载类。

三、每个类加载器加载类的时候,会先委托给上级类加载器,会从BootStrap开始查看这个类是否已经加载过,如果父类加载器没有加载过这个类,那么才会顺着继承关系逐级下来进行查看。

可以写一个java.lang.String类通过自己写的类加载器加载,但是这个类加载器就不是依托与虚拟机加载类了。因为如果依托于java虚拟机加载的话,java虚拟机中的类加载机制是委托机制,即最后会从BootStrap开始逐级查找要进行加载的类,如果在父类中先找到了这个类,java虚拟机就会加载这个类,那么我们写的这个类就根本不可能加载到。

数组类的 Class对象不是由类加载器创建的,而是由Java运行时根据需要自动创建。数组类的类加载器由Class.getClassLoader()返回,该加载器与其元素类型的类加载器是相同的;如果该元素类型是基本类型,则该数组类没有类加载器。

4. 自定义类加载器

自定义的类加载器必须继承ClassLoader

模板方法设计模式:loadClass:通过findClass方法按照委托机制查找对应的类,在通过父类加载器检查所请求的类后,如果找到了类,那么就立刻调用defineClass把找到的字节码转换为这个类的实例。如果经过父类的加载器检查所请求的类却没有找到,反而在自定义的类加载器中找到了这个类,那么就会通过自定义的类加载器中复写过的findClass来对类的字节码进行在操作,然后调用defineClass把找到的字节码转换为这个类的实例。

A. loadClass方法,不能覆盖

Class<?> loadClass(String name) 使用指定的类名来加载类。

protected Class<?> loadClass(Stringname,boolean resolve) 使用指定的二进制名称来加载类。

B. findClass方法,需要覆盖这个方法。该方法按照委托机制查找对应的类,在通过父类加载器检查所请求的类后,此方法将被loadClass方法调用

protected Class<?> findClass(Stringname)使用指定的二进制名称查找类。

例子:

package com.base.chapter4;
class Base{
public static int a = 10;
public int b = 20;
static
{
System.out.println("Static Init Base " + a);
//System.out.println("Null Init " + b);
}
public Base()
{
System.out.println("Init Base " + this.b);
}
}


class SuperClass extends Base{
//静态变量、静态块执行顺序,按书写先后顺序
public static int a1 = getSuperStaticNumber();
public int b1 = getSuperInstanceNumber();
public SuperClass()
{
System.out.println("Init SuperClass" + this.b1);
}
static
{
System.out.println("Static Init SuperClass" + a1);
}
public static int getSuperStaticNumber()
{
System.out.println("Static member init");
return 100;
}
public int getSuperInstanceNumber()
{
System.out.println("Instance member init");
return 200;
}
}
public class Sub extends SuperClass{
public static int a2 = getStaticNumber();
public int b2 = getInstanceNumber();
public Sub()
{
System.out.println("Init SubClass " + this.b2);
}
public static int getStaticNumber()
{
System.out.println("Static member init Sub");
return 1000;
}
public int getInstanceNumber()
{
System.out.println("Instance member init Sub");
return 2000;
}
static
{
System.out.println("Static Init " + a2);
}

public static void main(String args[])
{
new Sub();
}
}


结果:

Static Init Base 10

Static member init

Static Init SuperClass100

Static member init Sub

Static Init 1000

Init Base 20

Instance member init

Init SuperClass200

Instance member init Sub

Init SubClass 2000
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: