• 类加载器


    类加载器,通过一个类的全限定名来获取描述此类的二进制字节流

    第一类是启动类加载器(Bootstrap ClassLoader):这个类加载器主要加载JVM自身工作需要的 类。这个类加载器由C++语言实现(特指HotSpot),是虚拟机自身的一部分。负责将存放在%JAVA_HOME%lib目录中的,或者被 -Xbootclasspath参数所指定的路径中,并且是虚拟机识别的(仅按照文件名识别,如rt.jar,名字不符合的类库即使放在lib目录中也不 会被加载)类加载到虚拟机内存中。
      另一类就是所有其他的类加载器,这些加载器都是由java实现,独立于虚拟机外部。
      Extension ClassLoader:这个类即在其有sun.misc.Launcher$ExtClassLoader实现,它负责加载%JAVA_HOME%libext目录中,或者被java.ext.dirs系统变量所指定的路径中的所有类库,开发者可以直接使用扩展类加载器。
      Application ClassLoader:这个类加载器由sun.misc.Launcher$AppClassLoader 实现。由于这个类加载器是ClassLoader中的getSystemClassLoader()方法的返回值,所以一般也成它为系统类加载器。它负责 加载用户类路径上指定的类库,开发者可以直接使用这个类加载器,如果应用程序中没有自定义过自己的类加载器,一般情况下这个就是程序中默认的类加载器。
      AppClassLoader的parent是ExtClassLoader。很多文章在介绍ClassLoader层次的结构时把 Bootstrap ClassLoader也列在ExtClassLoader的上一级中,其实Bootstrap ClassLoader并不属于JVM的类等级层次,因为Bootstrap ClassLoader没有遵守ClassLoader的加载股则。另外Bootstrap ClassLoader没有子类,ExtClassLoader的父类也不是Bootstrap ClassLoader,ExtClassLoader并没有父类,我们在应用中能提取到的顶层父类是ExtClassLoader.

    双亲委派模型的工作过程是:如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,每一个层次的 类加载器都是如此,因此所有的加载请求最终都应该传送到顶层的启动类加载器中,只有当父加载器反馈自己无法完成这个加载请求(它搜索范围中没有找到所需的 类)时,子加载器才会尝试自己去加载。

    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;
            }
        }
    

     自定义类加载器:

      findClass()的功能是找到class文件并把字节码加载到内存中。自定义的ClassLoader一般覆盖改方法,以便使用不同的加载路径,然后调用defineClass()解析字节码。
      defineClass()方法用来将byte字节流解析成JVM能够识别的Class对象。有了这个方法意味着我们不仅仅可以通过class文件实 例化对象,还可以通过其他方式实例化对象,如我们通过网络接收到一个类的字节码,拿这个字节码流直接创建类的Class对象形式实例化对象。
      自定义的加载器可以覆盖方法loadClass()以便定义不同的加载机制。
      如果自定义的加载器仅覆盖了findClass(),而未覆盖loadClass(即加载规则一样,但加载路径不同);则调用 getClass().getClassLoader()返回的仍然是AppClassLoader!因为真正的load类,还是 AppClassLoader.

    package classloader;
    
    import java.io.ByteArrayOutputStream;
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.io.InputStream;
    
    public class ClassReloader extends ClassLoader
    {
        private String classPath;
        String classname = "classloader.SingleClass";
    
        public ClassReloader(String classpath)
        {
            this.classPath = classpath;
        }
    
        protected Class<?> findClass(String name) throws ClassNotFoundException{
            byte [] classData = getData(name);
            if(classData == null)
            {
                throw new ClassNotFoundException();
            }
            else
            {
     return defineClass(classname,classData,0,classData.length);
            }
        }
    
        private byte[] getData(String className)
        {
            String path = classPath+className;
            try
            {
                InputStream is = new FileInputStream(path);
                ByteArrayOutputStream stream = new ByteArrayOutputStream();
                byte[] buffer = new byte[2048];
                int num = 0;
                while((num = is.read(buffer))!=-1)
                {
                    stream.write(buffer,0,num);
                }
                return stream.toByteArray();
            }
            catch(IOException e)
            {
                e.printStackTrace();
            }
            return null;
        }
    
        public static void main(String[] args)
        {
            try
            { String path = "D:/workspace_jee/JavaTest/src/classloader/";
                ClassReloader reloader = new ClassReloader(path);
                Class r = reloader.findClass("SingleClass.class");
                System.out.println(r.newInstance());
    //            ClassReloader reloader2 = new ClassReloader(path);
                Class r2 = reloader.findClass("SingleClass.class");
                System.out.println(r2.newInstance());
            }
            catch (ClassNotFoundException | InstantiationException | IllegalAccessException e)
            {
                e.printStackTrace();
            }
        }
    }
  • 相关阅读:
    1.C和C++区别,以及const分析(底层const/顶层const)
    4.移植驱动到3.4内核-移植总结
    3.移植驱动到3.4内核-移植DM9000C驱动
    2.移植3.4内核-支持烧写yaffs2,裁剪内核并制作补丁
    Android Support v4、v7、v13、v14、v17的区别和应用场景
    Android利用canvas画各种图形
    ActionBar 自定义布局定义
    android动画坐标定义
    GitHub上最著名的Android播放器开源项目大全
    CardView 简介和使用
  • 原文地址:https://www.cnblogs.com/lelouchKOP/p/5810671.html
Copyright © 2020-2023  润新知