类加载器简介

类加载器简介,第1张

加载器简介

类加载器是用于加载类的对象,ClassLoader是一个抽象类。如果我们给定了一个类的二进制名称,类加载器应尝试去定位或生成构成定义类的数据。一种典型的策略是将给定的二进制名称转换为文件名,然后去文件系统中读取这个文件名所对应的class文件。

 

 

每个Class对象都会包含一个定义它的ClassLoader的一个引用。

 

数组类的Class对象,不是由类加载器去创建的,而是在Java运行期JVM根据需要自动创建的。对于数组类的类加载器来说,是通过Class.getClassLoader()返回的,与数组当中元素类型的类加载器是一样的;如果数组当中的元素类型是一个原生类型,数组类是没有类加载器的【代码一】。

 

应用实现了ClassLoader的子类是为了扩展JVM动态加载类的方式。

 

类加载器典型情况下时可以被安全管理器所使用去标识安全域问题。

 

ClassLoader类使用了委托模型来寻找类和资源,ClassLoader的每一个实例都会有一个与之关联的父ClassLoader,当ClassLoader被要求寻找一个类或者资源的时候,ClassLoader实例在自身尝试寻找类或者资源之前会委托它的父类加载器去完成。虚拟机内建的类加载器,称之为启动类加载器,是没有父加载器的,但是可以作为一个类加载器的父类加载器【双亲委托机制】。

 

支持并发类加载的类加载器叫做并行类加载器,要求在初始化期间通过**ClassLoader.registerAsParallelCapable **方法注册自身,ClassLoader类默认被注册为可以并行,但是如果它的子类也是并行加载的话需要单独去注册子类。

 

在委托模型不是严格的层次化的环境下,类加载器需要并行,否则类加载会导致死锁,因为加载器的锁在类加载过程中是一直被持有的。

 

通常情况下,Java虚拟机以平台相关的形式从本地的文件系统中加载类,比如在UNIX系统,虚拟机从CLASSPATH环境所定义的目录加载类。

然而,有些类并不是来自于文件;它们是从其它来源得到的,比如网络,或者是由应用本身构建【动态代理】。定义类(defineClass )方法会将字节数组转换为Class的实例,这个新定义类的实例可以由Class.newInstance创建。

 

由类加载器创建的对象的方法和构造方法可能引用其它的类,为了确定被引用的类,Java虚拟机会调用最初创建类的类加载器的loadClass方法。

 

二进制名称:以字符串参数的形式向CalssLoader提供的任意一个类名,必须是一个二进制的名称,包含以下四种情况

 

"java.lang.String" 正常类

"javax.swing.JSpinner$DefaultEditor" 内部类

"java.security.KeyStoreBuilderBuilderFileBuilder$1" KeyStore的内部类Builder的内部类FileBuilder的第一个匿名内部类

"java.net.URLClassLoader331" URLClassLoader类的第三个匿名内部类的第一个匿名内部类

代码一:

 

 

public class Test12 {

    public static void main(String[] args) {

        String[] strings = new String[6];

        System.out.println(strings.getClass().getClassLoader());

        // 运行结果:null

 

        Test12[] test12s = new Test12[1];

        System.out.println(test12s.getClass().getClassLoader());

        // 运行结果:sun.misc.Launcher$AppClassLoader@18b4aac2

 

        int[] ints = new int[2];

        System.out.println(ints.getClass().getClassLoader());

        // 运行结果:null

    }

}

 

2|2loadClass方法

loadClass的源码如下, loadClass方法加载拥有指定的二进制名称的Class,默认按照如下顺序寻找类:

 

调用findLoadedClass(String)检查这个类是否被加载

调用父类加载器的loadClass方法,如果父类加载器为null,就会调用启动类加载器

调用findClass(String)方法寻找

使用上述步骤如果类被找到且resolve为true,就会去调用resolveClass(Class)方法

 

 

protected Class loadClass(String name, boolean resolve)

  throws ClassNotFoundException

{

  synchronized (getClassLoadingLock(name)) {

      // First, check if the class has already been loaded

      Class c = findLoadedClass(name);

      if (c == null) {

          long t0 = System.nanoTime();

          try {

              if (parent != null) {

                  c = parent.loadClass(name, false);

              } else {

                  c = findBootstrapClassOrNull(name);

              }

          } catch (ClassNotFoundException e) {

              // ClassNotFoundException thrown if class not found

              // from the non-null parent class loader

          }

 

          if (c == null) {

              // If still not found, then invoke findClass in order

              // to find the class.

              long t1 = System.nanoTime();

              c = findClass(name);

 

              // this is the defining class loader; record the stats

              sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);

              sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);

              sun.misc.PerfCounter.getFindClasses().increment();

          }

      }

      if (resolve) {

          resolveClass(c);

      }

      return c;

  }

}

 

2|3findClass方法

findClass的源码如下,findClass寻找拥有指定二进制名称的类,JVM鼓励我们重写此方法,需要自定义加载器遵循双亲委托机制,该方法会在检查完父类加载器之后被loadClass方法调用,默认返回ClassNotFoundException异常。

 

 

protected Class findClass(String name) throws ClassNotFoundException {

    throw new ClassNotFoundException(name);

}

 

2|4defineClass方法

defineClass的源码如下,defineClass方法将一个字节数组转换为Class的实例。

 

 

protected final Class defineClass(String name, byte[] b, int off, int len,

                                     ProtectionDomain protectionDomain)

    throws ClassFormatError

{

    protectionDomain = preDefineClass(name, protectionDomain);

    String source = defineClassSourceLocation(protectionDomain);

    Class c = defineClass1(name, b, off, len, protectionDomain, source);

    postDefineClass(c, protectionDomain);

    return c;

}

 

3|0自定义类加载器

 

public class ClassLoaderTest extends ClassLoader {

    public static void main(String[] args) throws Exception {

        ClassLoaderTest loader = new ClassLoaderTest("loader");

       Class clazz = loader.loadClass("classloader.Test01");

        Object object = clazz.newInstance();

        System.out.println(object);

        System.out.println(object.getClass().getClassLoader());

    }

    //------------------------------以上为测试代码---------------------------------

 

   

    private String classLoaderName;

 

   

    private String fileExtension = ".class";

 

   

    private ClassLoaderTest(String classLoaderName) {

        // 将系统类加载器当做该类加载器的父加载器

        super();

        this.cla

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5717892.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存