zoukankan      html  css  js  c++  java
  • 自定义类加载器在复杂类加载情况下的运行分析

    在之前咱们都在研究自定义类加载器的一些东东,不过接一来的学习还会依托于之前咱们写的MyTest16这个自定义类加载器,这里先再回顾一下:

    public class MyTest16 extends ClassLoader {
        private String classLoaderName;
        /* 从什么地方去加载,这是个绝对路径 */
        private String path;
    
        private final String fileExtension = ".class";//要加载的字节码文件的扩展名
    
        public MyTest16(String classLoaderName) {
            super();//将系统类加载器当作该类加载器的父加载器
            this.classLoaderName = classLoaderName;
        }
    
        public MyTest16(ClassLoader parent, String classLoaderName) {
            super(parent);//显示指定该类加载器的父加载器
            this.classLoaderName = classLoaderName;
        }
    
        public void setPath(String path) {
            this.path = path;
        }
    
        @Override
        public String toString() {
            return "[" + classLoaderName + "]";
        }
    
        @Override
        protected Class<?> findClass(String className) throws ClassNotFoundException {
            System.out.println("findClass invoked: " + className);
            System.out.println("class loader name: " + this.classLoaderName);
            byte[] data = this.loadClassData(className);
            return this.defineClass(className, data, 0, data.length);
        }
    
        private byte[] loadClassData(String className) {
            InputStream is = null;
            byte[] data = null;
            ByteArrayOutputStream baos = null;
    
            className = className.replace(".", "/");//由于路径名需要以/分隔,而不是像包名以.分隔的
    
            try {
                is = new FileInputStream(new File(this.path + className + this.fileExtension));
                baos = new ByteArrayOutputStream();
    
                int ch = 0;
    
                while (-1 != (ch = is.read())) {
                    baos.write(ch);
                }
    
                data = baos.toByteArray();
    
            } catch (Exception ex) {
                ex.printStackTrace();
            } finally {
                try {
                    is.close();
                    baos.close();
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
    
    
            return data;
        }
    
        public static void main(String[] args) throws Exception {
            MyTest16 loader1 = new MyTest16("loader1");
            Class<?> clazz = loader1.loadClass("com.jvm.classloader.MyTest1");
            System.out.println("class:" + clazz.hashCode());
            System.out.println("classloader:" + clazz.getClassLoader());
            Object object = clazz.newInstance();
            System.out.println(object);
    
            System.out.println();
        }
    }

    而对于之前咱们加载的类都是一个比较简单的类,如MyTest1:

    但是在日常开发中可能常见的用法是方法里面会使用其它的类,那如果是这种情况类的加载的流程是一个什么情况呢,下面来探讨一下:

    首先新建一个MyCat类:

     

    然后再新建一个MySample类:

    目前这两个类木有任何关系,接下来将其关联起来:

    好,接下来应用一下:

    其结果:

    很明显由于MySample的字节码文件存在于工程当中,所以肯定是由系统类加载了,接下来将这句代码注释掉:

    编译运行:

    也就是注释之后则不会实例化MySample对象,既MySample构造方法不会被调用,因此也不会实例化MyCat对象,既没有对MyCat进行主动使用,这里就不会加载MyCat Class。其实类加载器会不会加载MyCat这是不一定的,这是因为如下原因:

    • 类加载器并不需要等到某个类被“首次主动使用”时再加载它。
    • JVM规范允许类加载器在预料某个类将要被使用时就预先加载它,如果在预先加载的过程中遇到了.class文件缺失或存在错误,类加载器必须在程序首次主动使用该类时才报告错误(LinkageError错误)。
    • 如果这个类一直没有被程序主动使用,那么类加载器就不会报告错误

    所以MyCat类虽说没有被初始化,那它到底有木有被加载可以通过给JVM增加"-XX:+TraceClassLoading"来看一下:

    但是这不代表JVM一定不会加载MyCat这个类,需要注意。

  • 相关阅读:
    如何在centos上安装epel源
    Linux基础命令之cat使用方法大全
    Python正则表达式一: 基本使用方法
    Python 2.7 学习笔记 中文处理
    python 中 json的处理
    centos下网络代理服务器的配置
    centos7 在 vmware下的安装与配置
    Linux学习:find、chmod、ps命令
    Linux学习:netstat命令
    Linux学习:curl 与 wget命令
  • 原文地址:https://www.cnblogs.com/webor2006/p/9129149.html
Copyright © 2011-2022 走看看