• ClassLoader


    java中的类加载器:bootstrap,ExtClassLoader,AppClassLoader
    bootstrap 使用c++编写
    sun.misc.Launcher.ExtClassLoader
    sun.misc.Launcher.AppClassLoader

    继承关系:

    ClassLoader -> SecureClassLoader -> URLClassLoader -> sun.misc.Launcher$AppClassLoader

    ClassLoader -> SecureClassLoader -> URLClassLoader -> sun.misc.Launcher$ExtClassLoader

    下面一段话翻译自Javassist Tutorial:
        在java中,多个class loader可以共存,每一个class loader创建自己的命名空间。不同的类加载器可以加载同名的但内容不同的class文件。加载的2个类被认为是不同的。这个特性使我们可以在单个jvm内部运行不同的程序,即使这些程序包含同名的class。

      (注意:jvm不允许动态加载类。一旦一个class loader加载了某个类,该class loader不能在运行期内加载修改过的类。所以在jvm加载这个类后,你不能修改它的定义了。JPDA (Java Platform Debugger Architecture)提供了有限的重载一个类的能力。)

        如果同一个class文件被两个不同的class loader加载了,jvm会使用相同的名字和定义创建两个不同的class对象。这两个class被认为是不同的。因为这两个类是不同的,一个类的实例不能赋值给另一个类的变量。 两个类之间的转换操作会失败,并抛ClassCastException异常。
    例如:下面的代码片段会抛出异常。
    MyClassLoader myLoader = new MyClassLoader();
    Class clazz = myLoader.loadClass("Box");
    Object obj = clazz.newInstance();
    Box b = (Box)obj;    // this always throws ClassCastException.


    上面的话,用一幅图表示:

    我们知道bootstrap是ExtClassLoader的父亲,ExtClassLoader是AppClassLoader的父亲,bootstrap负责rt.jar,ExtClassLoader负责ext目录中的jar,而AppClassLoader加载我们自己写的类。加载类的时候呢,使用的是双亲委派机制,先给父亲加载,在父亲的管辖范围内呢,父亲就会加载,反之则自己加载这个类。

    但是,我们自己定义的类加载器,可以不使用双亲委派机制。

    以下是一个自定义类加载器,from(https://yq.aliyun.com/articles/55616):

    class MyClassLoader extends ClassLoader {
        @Override
        public Class<?> loadClass(String name) throws ClassNotFoundException {
            try {
                String fileName = name.substring(name.lastIndexOf(".") + 1) + ".class";
                InputStream is = getClass().getResourceAsStream(fileName);
                if (is == null) {
                    return super.loadClass(name);
                }
                byte[] b = new byte[is.available()];
                is.read(b);
                return defineClass(name, b, 0, b.length);
            }
            catch (Exception e) {
                throw new ClassNotFoundException(name);
            }
        }
    }

    线程内部有一个上下文类加载器:

    public class Thread implements Runnable {
       /* The context ClassLoader for this thread */
        private ClassLoader contextClassLoader;
    }

    改变当前线程的contextClassLoader后,从当前线程派生出的子线程则使用修改后的contextClassLoader。

    从类的Class对象可以获得加载该类的ClassLoader,从线程能获取该线程的contextClassLoader。

    public class ClassLoader_Test {
        public static void main(String[] args) throws ClassNotFoundException {
            System.out.println(ClassLoader_Test.class.getClassLoader());
            System.out.println(Thread.currentThread().getContextClassLoader());
        }
    }

    平常,我们习惯用 Class.forName("xxx") 获取类的Class对象,其底层是调用ClassLoader.loadClass方法。

  • 相关阅读:
    Hive数据倾斜原因和解决办法(Data Skew)
    Hive简介
    SQL---公共表表达式(CTEs)
    SQL面试题---topN问题
    SQL---分页查询
    SQL---自连接(self join)
    SQL---关联子查询(correlated subquery)
    SQL---CASE表达式
    SQL查询语句执行顺序
    SQL---窗口函数(window function)
  • 原文地址:https://www.cnblogs.com/allenwas3/p/8350193.html
Copyright © 2020-2023  润新知