jvm 类加载机制 之抽象类ClassLoader介绍 (6)

public abstract class ClassLoader {
    // 要为类注册本地函数,RegisterNatives从本地的库中的本机代码调用JNI函数。
    private static native void registerNatives();
    static {
        registerNatives();
    }
    /*
     * 委托的父类装入器
     * 注意:虚拟机硬编码这个字段的偏移量,
     * 因此,所有新字段必须在*after*添加。
     */
    private final ClassLoader parent;
    /**
     * 封装可并行加载器类型集
     */
    private static class ParallelLoaders {
        private ParallelLoaders() {}
        // 一组具有并行能力的加载器类型
        private static final Set<Class<? extends ClassLoader>> loaderTypes =
            Collections.newSetFromMap(
                new WeakHashMap<Class<? extends ClassLoader>, Boolean>());
        static {
            synchronized (loaderTypes) { loaderTypes.add(ClassLoader.class); }
        }
        /**
         * 将给定的类加载器类型注册为并行capabale。
         * 成功注册返回true;
         * 如果加载器的超类未注册,则为false。
         */
        static boolean register(Class<? extends ClassLoader> c) {
            synchronized (loaderTypes) {
                if (loaderTypes.contains(c.getSuperclass())) {
                    /*
                     * 注册类加载器为并行的,当且仅当它的所有超类都是并行的。
                     * 注:给定当前类加载顺序,如果直接超类是并行的,
                     * 上面的所有超类也必须是。
                     */
                    loaderTypes.add(c);
                    return true;
                } else {
                    return false;
                }
            }
        }
        /**
         * 如果指定的类加载器类型注册为并行的,则返回{true}。
         */
        static boolean isRegistered(Class<? extends ClassLoader> c) {
            synchronized (loaderTypes) {
                return loaderTypes.contains(c);
            }
        }
    }
    /*
     * 当当前类加载器具有并行能力时,将类名映射到相应的锁对象。
     * 注意:VM还使用这个字段来决定当前类加载器是否具有并行能力,以及加载类的适当锁定对象。
     */
    private final ConcurrentHashMap<String, Object> parallelLockMap;
    // 将包映射到certs的哈希表
    private final Map <String, Certificate[]> package2certs;
    // 在所有无签名类的包之间共享
    private static final Certificate[] nocerts = new Certificate[0];
    /*
     * 由这类加载器加载的类。
     * 此表的唯一目的是在加载器GC之前防止类被GC。
     */
    private final Vector<Class<?>> classes = new Vector<>();
    /*
     * “默认”domain。
     * 设置为新创建的类的默认ProtectionDomain。
     */
    private final ProtectionDomain defaultDomain =
        new ProtectionDomain(new CodeSource(null, (Certificate[]) null),
                             null, this, null);
    // 此加载程序加载的所有类的初始化保护domain
    private final Set<ProtectionDomain> domains;
    /**
     * VM调用它来记录使用此加载器加载的每个类。
     * @param c
     */
    void addClass(Class<?> c) {
        classes.addElement(c);
    }
    /*
     * 类加载器中定义的包。
     * 每个包名映射到对应的包对象。
     */
    private final HashMap<String, Package> packages = new HashMap<>();
    /**
     * 检查创建新类加载器的权限
     * @return
     */
    private static Void checkCreateClassLoader() {
        // 获取系统安全接口
        SecurityManager security = System.getSecurityManager();
        if (security != null) {
            // 判断是否有调用线程创建新类加载器的权限,不允许,则抛SecurityException
            security.checkCreateClassLoader();
        }
        return null;
    }
    /**
     * 私有构造器
     * @param unused
     * @param parent
     */
    private ClassLoader(Void unused, ClassLoader parent) {
        this.parent = parent;
        // 如果指定的类加载器类型注册为并行的,则返回true。
        if (ParallelLoaders.isRegistered(this.getClass())) {
            parallelLockMap = new ConcurrentHashMap<>();
            package2certs = new ConcurrentHashMap<>();
            domains =
                Collections.synchronizedSet(new HashSet<ProtectionDomain>());
            assertionLock = new Object();
        } else {
             // 没有更细粒度的锁;锁定类加载器实例
            parallelLockMap = null;
            package2certs = new Hashtable<>();
            domains = new HashSet<>();
            assertionLock = this;
        }
    }
 
    /**
     * 使用指定的、用于委托操作的父类加载器创建新的类加载器。 
     * 如果存在安全管理器,则调用其 checkCreateClassLoader 方法。这可能导致安全性异常。
     * @param parent    父类加载器 
     */    
    protected ClassLoader(ClassLoader parent) {
        this(checkCreateClassLoader(), parent);
    }
 
    /**
     * 使用方法 getSystemClassLoader() 返回的 ClassLoader 创建一个新的类加载器,将该加载器作为父类加载器。 
     * 如果存在安全管理器,则调用其 checkCreateClassLoader 方法。这可能导致安全性异常。 
     */
    protected ClassLoader() {
        this(checkCreateClassLoader(), getSystemClassLoader());
    }
 
    // -- Class --
 
    /**
     * 使用指定的二进制名称来加载类。此方法使用与 loadClass(String, boolean) 方法相同的方式搜索类。
     * Java 虚拟机调用它来分析类引用。调用此方法等效于调用 loadClass(name, false)。
     * @param name    类的二进制名称 
     * @return
     * @throws ClassNotFoundException
     */
    public Class<?> loadClass(String name) throws ClassNotFoundException {
        return loadClass(name, false);
    }
 
    /**
     * 使用指定的二进制名称来加载类。此方法的默认实现将按以下顺序搜索类: 
     * 调用 findLoadedClass(String) 来检查是否已经加载类。
     * 在父类加载器上调用 loadClass 方法。如果父类加载器为 null,则使用虚拟机的内置类加载器。 
     * 调用 findClass(String) 方法查找类。
     * 如果使用上述步骤找到类,并且 resolve 标志为真,则此方法将在得到的 Class 对象上调用 resolveClass(Class) 方法。 
     * 鼓励用 ClassLoader 的子类重写 findClass(String),而不是使用此方法。
     * @param name    类的二进制名称
     * @param resolve    如果该参数为 true,则分析这个类 
     * @return
     * @throws ClassNotFoundException
     */
    protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
        synchronized (getClassLoadingLock(name)) {
            // 首先,检查类是否已经加载
            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
                }
 
                if (c == null) {
                        // 如果仍然没有找到,然后调用findClass来查找该类。
                    long t1 = System.nanoTime();
                    c = findClass(name);
 
                        // 这是定义类加载器;记录数据
                    sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                    sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                    sun.misc.PerfCounter.getFindClasses().increment();
                }
            }
            if (resolve) { // 链接指定的类。
                resolveClass(c);
            }
            return c;
        }
    }
 
    /**
     * 返回类加载操作的锁对象。
     * 为了向后兼容,此方法的默认实现的行为如下。
     * 如果这个类加载器对象被注册为并行的,该方法返回与指定类名关联的专用对象。否则,该方法返回这个类加载器对象。
     * @param className    要加载的类的名称
     * @return    类加载操作的锁
     */
    protected Object getClassLoadingLock(String className) {
        Object lock = this;
        if (parallelLockMap != null) {
            Object newLock = new Object();
            // 如果指定键已经不再与某个值相关联,则将它与给定值关联。
            lock = parallelLockMap.putIfAbsent(className, newLock);
            if (lock == null) {
                lock = newLock;
            }
        }
        return lock;
    }
 
    /**
     * 虚拟机调用此方法来加载类。
     * @param name    类的二进制名称 
     * @return
     * @throws ClassNotFoundException
     */
    private Class<?> loadClassInternal(String name)
        throws ClassNotFoundException
    {
            // 为了向后兼容,当当前类加载器不支持并行时,显式锁定“this”。
        if (parallelLockMap == null) {
            synchronized (this) {
                 return loadClass(name);
            }
        } else {
            return loadClass(name);
        }
    }
 
    /**
     * 在使用此加载器加载类之后由VM调用。
     * @param cls
     * @param pd
     */
    private void checkPackageAccess(Class<?> cls, ProtectionDomain pd) {
        final SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            // 是否有保护域拥有权限
            if (ReflectUtil.isNonPublicProxyClass(cls)) {
                for (Class<?> intf: cls.getInterfaces()) {
                    checkPackageAccess(intf, pd);
                }
                return;
            }
 
            final String name = cls.getName();
            final int i = name.lastIndexOf('.');
            if (i != -1) {
                /*
                 * 通过指定的 AccessControlContext 启用和限制特权,执行指定的 PrivilegedAction。
                 * 该操作在调用方保护域所拥有权限与指定的 AccessControlContext 表示的域所拥有权限的交集下执行。 
                 */
                AccessController.doPrivileged(new PrivilegedAction<Void>() {
                    public Void run() {
                        // 如果不允许调用线程访问由参数指定的包,则抛出 SecurityException。 
                        sm.checkPackageAccess(name.substring(0, i));
                        return null;
                    }
                    // 创建带有给定 ProtectionDomain 集合的 AccessControlContext。上下文不能为 null。重复的域将从上下文中被移除。 
                }, new AccessControlContext(new ProtectionDomain[] {pd}));
            }
        }
        domains.add(pd);
    }
 
    /**
     * 使用指定的二进制名称查找类。此方法应该被类加载器的实现重写,该实现按照委托模型来加载类。
     * 在通过父类加载器检查所请求的类后,此方法将被 loadClass 方法调用。
     * @param name    类的二进制名称 
     * @return
     * @throws ClassNotFoundException
     */
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        throw new ClassNotFoundException(name);
    }
 
    /**
     * 将一个 byte 数组转换为 Class 类的实例。必须分析 Class,然后才能使用它。 
     * 此方法将默认的 ProtectionDomain 分配给新定义的类。
     * 调用 Policy.getPolicy().getPermissions(new CodeSource(null, null)) 时,
     * ProtectionDomain 被有效授予所返回的相同权限集。
     * 默认域在第一次调用 defineClass 时创建,并在后续调用时被重用。 
     * 要将特定的 ProtectionDomain 分配给类,需要使用 defineClass 方法,
     * 该方法将 ProtectionDomain 用作其参数之一。 
     * @param name    所需要的类的二进制名称,如果不知道此名称,则该参数为 null
     * @param b    组成类数据的字节。
     * @param off    类数据的 b 中的起始偏移量
     * @param len    类数据的长度 
     * @return
     * @throws ClassFormatError
     */
    protected final Class<?> defineClass(String name, byte[] b, int off, int len)
        throws ClassFormatError
    {
        return defineClass(name, b, off, len, null);
    }
 
    /**
     * 确定ProtectionDomain,并检查。
     * @param name
     * @param pd
     * @return
     */
    private ProtectionDomain preDefineClass(String name,
                                            ProtectionDomain pd)
    {
        //如果名称为null或可能为有效二进制名称,则为true
        if (!checkName(name))
            throw new NoClassDefFoundError("IllegalName: " + name);
 
        // 指定的 name 不能以 "java." 开头,因为 "java.*" 包中的所有类都只能由引导类加载器定义。
        if ((name != null) && name.startsWith("java.")) {
            throw new SecurityException
                ("Prohibited package name: " +
                 name.substring(0, name.lastIndexOf('.')));
        }
        if (pd == null) {
            pd = defaultDomain;
        }
        // 如果 name 不是 null,则它必定等于由 byte 数组 "b" 指定的类的二进制名称
        if (name != null) checkCerts(name, pd.getCodeSource());
 
        return pd;
    }
    /**
     * 获取与此 域的CodeSource 关联的位置
     * @param pd
     * @return
     */
    private String defineClassSourceLocation(ProtectionDomain pd)
    {
        // 获取此域的 CodeSource。 
        CodeSource cs = pd.getCodeSource();
        String source = null;
        if (cs != null && cs.getLocation() != null) {
            // 获取与此 CodeSource 关联的位置
            source = cs.getLocation().toString();
        }
        return source;
    }
    /**
     * 从该类的 ProtectionDomain 中的 CodeSource 可以获得类的证书集合。
     * 添加到该包中的任何类都必须包含相同的证书集合
     * @param c
     * @param pd
     */
    private void postDefineClass(Class<?> c, ProtectionDomain pd)
    {
        if (pd.getCodeSource() != null) {
            // 获取与此 CodeSource 关联的证书。
            Certificate certs[] = pd.getCodeSource().getCertificates();
            if (certs != null)
            // 设置类的签署者
                setSigners(c, certs);
        }
    }
 
   /**
     * 使用可选的 ProtectionDomain 将一个 byte 数组转换为 Class 类的实例。
     * 如果该域为 null,则将默认域分配给 defineClass(String, byte[], int, int) 的文档中指定的类。
     * 这个类必须分析后才能使用。 
     * 包中定义的第一个类确定在该包中定义的所有后续类必须包含的证书的确切集合。
     * 从该类的 ProtectionDomain 中的 CodeSource 可以获得类的证书集合。
     * 添加到该包中的任何类都必须包含相同的证书集合,否则抛出 SecurityException 异常。
     * 注意,如果 name 为 null,则不执行该检查。应该始终传入要定义的类的二进制名称以及字节。
     * 这可确保定义该类的正确性。 
     * 指定的 name 不能以 "java." 开头,因为 "java.*" 包中的所有类都只能由引导类加载器定义。
     * 如果 name 不是 null,则它必定等于由 byte 数组 "b" 指定的类的二进制名称,
     * 否则将抛出 NoClassDefFoundError。 
     * @param name    所需类的二进制名称,如果不知道此名称,则该参数为 null
     * @param b    组成类数据的字节。
     * @param off    类数据的 b 中的起始偏移量
     * @param len    类数据的长度
     * @param protectionDomain    类的 ProtectionDomain 
     * @return
     * @throws ClassFormatError
     */
    protected final Class<?> defineClass(String name, byte[] b, int off, int len,
                                         ProtectionDomain protectionDomain)
        throws ClassFormatError
    {
        // 确定ProtectionDomain,分析
        protectionDomain = preDefineClass(name, protectionDomain);
    // 获取与此 域的CodeSource 关联的位置
        String source = defineClassSourceLocation(protectionDomain);
    // 获取class对象,通过b为byte[]
        Class<?> c = defineClass1(name, b, off, len, protectionDomain, source);
    // 从该类的 ProtectionDomain 中的 CodeSource 可以获得类的证书集合。
    // 添加到该包中的任何类都必须包含相同的证书集合
        postDefineClass(c, protectionDomain);
        return c;
    }
 
    /**
     * 使用可选的 ProtectionDomain 将 ByteBuffer 转换为 Class 类的实例。
     * 如果该域为 null,则将默认域分配给 defineClass(String, byte[], int, int) 的文档中指定的类。
     * 这个类必须分析后才能使用。 
     * 有关包中定义的第一个类(它确定了包的证书集合)的规则,以及对类名称的限制,
     * 都与 defineClass(String, byte[], int, int, ProtectionDomain) 的文档中指定的相同。 
     * @param name    所需要的类的二进制名称,如果不知道此名称,则该参数为 null
     * @param b    组成类数据的字节。
     * @param protectionDomain    类的 ProtectionDomain,或为 null。 
     * @return
     * @throws ClassFormatError
     */
    protected final Class<?> defineClass(String name, java.nio.ByteBuffer b,
                                         ProtectionDomain protectionDomain)
        throws ClassFormatError
    {
    // 获取此缓冲区中的剩余元素数
        int len = b.remaining();
 
    // 如果不是直接ByteBufer,请使用byte[]:
    // 判断此缓冲区是否为直接缓冲区。
        if (!b.isDirect()) {
            // 判断当且仅当此缓冲区有非只读的底层实现数组时返回 true。
            if (b.hasArray()) {
                return defineClass(name, b.array(),
                                   b.position() + b.arrayOffset(), len,
                                   protectionDomain);
            } else {
                // 不是数组, 或者 只读数组
                byte[] tb = new byte[len];
                b.get(tb);   //从字节缓冲区获取字节。
                return defineClass(name, tb, 0, len, protectionDomain);
            }
        }
    // 确定ProtectionDomain,并检查。
        protectionDomain = preDefineClass(name, protectionDomain);
    // 获取与此 域的CodeSource 关联的位置
        String source = defineClassSourceLocation(protectionDomain);
    // 获取class对象,通过b为nio.ByteBuffer字节缓冲
        Class<?> c = defineClass2(name, b, b.position(), len, protectionDomain, source);
    // 从该类的 ProtectionDomain 中的 CodeSource 可以获得类的证书集合。
    // 添加到该包中的任何类都必须包含相同的证书集合
        postDefineClass(c, protectionDomain);
        return c;
    }
 
    private native Class<?> defineClass0(String name, byte[] b, int off, int len,
                                         ProtectionDomain pd);
 
    private native Class<?> defineClass1(String name, byte[] b, int off, int len,
                                         ProtectionDomain pd, String source);
 
    private native Class<?> defineClass2(String name, java.nio.ByteBuffer b,
                                         int off, int len, ProtectionDomain pd,
                                         String source);
 
    /**
     * 如果名称为null或可能为有效二进制名称,则为true
     * @param name
     * @return
     */
    private boolean checkName(String name) {
        if ((name == null) || (name.length() == 0))
            return true;
        if ((name.indexOf('/') != -1)
            || (!VM.allowArraySyntax() && (name.charAt(0) == '[')))
            return false;
        return true;
    }
    /**
     * 检查name是否等于由 byte 数组 "b" 指定的类的二进制名称
     * @param name
     * @param cs
     */
    private void checkCerts(String name, CodeSource cs) {
        int i = name.lastIndexOf('.');
        String pname = (i == -1) ? "" : name.substring(0, i);
 
        Certificate[] certs = null;
        if (cs != null) {
            // // 获取与此 CodeSource 关联的证书。
            certs = cs.getCertificates();
        }
        Certificate[] pcerts = null;
        if (parallelLockMap == null) {
            // 放入与当前类加载器关联的package2certs中
            synchronized (this) {
                pcerts = package2certs.get(pname);
                if (pcerts == null) {
                    package2certs.put(pname, (certs == null? nocerts:certs));
                }
            }
        } else {
            // 如果指定键已经不再与某个值相关联,则将它与给定值关联。
            pcerts = ((ConcurrentHashMap<String, Certificate[]>)package2certs).
                putIfAbsent(pname, (certs == null? nocerts:certs));
        }
        // 检查以确保新类(certs)的证书与包中插入的第一个类(pcerts)的证书相同
        if (pcerts != null && !compareCerts(pcerts, certs)) {
            throw new SecurityException("class \""+ name +
                 "\"'s signer information does not match signer information of other classes in the same package");
        }
    }
 
    /**
     * 检查以确保新类(certs)的证书与包中插入的第一个类(pcerts)的证书相同
     * @param pcerts
     * @param certs
     * @return
     */
    private boolean compareCerts(Certificate[] pcerts,
                                 Certificate[] certs)
    {
        // certs 可以为null, 表示没有certs
        if ((certs == null) || (certs.length == 0)) {
            return pcerts.length == 0;
        }
 
        // 这一点的长度必须相同
        if (certs.length != pcerts.length)
            return false;
 
        // 检查并确保一个数组中的所有certs都在另一个数组中,反之亦然。
        boolean match;
        for (int i = 0; i < certs.length; i++) {
            match = false;
            for (int j = 0; j < pcerts.length; j++) {
                if (certs[i].equals(pcerts[j])) {
                    match = true;
                    break;
                }
            }
            if (!match) return false;
        }
 
        // 现在对pcert做同样的事情
        for (int i = 0; i < pcerts.length; i++) {
            match = false;
            for (int j = 0; j < certs.length; j++) {
                if (pcerts[i].equals(certs[j])) {
                    match = true;
                    break;
                }
            }
            if (!match) return false;
        }
 
        return true;
    }
 
    /**
     * 链接指定的类。类加载器可以使用此方法(其名称容易使人误解)来链接类。
     * 如果已经链接类 c,则仅返回此方法。
     * @param c    要链接的类 
     */
    protected final void resolveClass(Class<?> c) {
        resolveClass0(c);
    }
 
    private native void resolveClass0(Class<?> c);
 
    /**
     * 查找具有指定的二进制名称的类,必要时加载它。 
     * 此方法通过系统类加载器(参见 getSystemClassLoader())来加载该类。
     * 返回的 Class 对象具有多个与之相关联的 ClassLoader。ClassLoader 的子类通常不必调用此方法,
     * 因为大多数类加载器只需重写 findClass(String) 即可。
     * @param name    类的二进制名称 
     * @return    指定 name 的 Class 对象
     * @throws ClassNotFoundException
     */
    protected final Class<?> findSystemClass(String name)
        throws ClassNotFoundException
    {
            // 获取委托的系统类加载器。
        ClassLoader system = getSystemClassLoader();
        if (system == null) {
                // 如果名称为null或可能为有效二进制名称,则为true
            if (!checkName(name))
                throw new ClassNotFoundException(name);
            Class<?> cls = findBootstrapClass(name);
            if (cls == null) {
                throw new ClassNotFoundException(name);
            }
            return cls;
        }
            // 使用指定的二进制名称来加载类。
        return system.loadClass(name);
    }
 
    /**
     * 使用虚拟机的内置类加载器加载类
     * @param name
     * @return
     */
    private Class<?> findBootstrapClassOrNull(String name)
    {
        // 如果名称为null或可能为有效二进制名称,则为true
        if (!checkName(name)) return null;
 
        return findBootstrapClass(name);
    }
 
    // 如果没有找到,返回null
    private native Class<?> findBootstrapClass(String name);
 
    /**
     * 如果 Java 虚拟机已将此加载器记录为具有给定二进制名称的某个类的启动加载器,
     * 则返回该二进制名称的类。否则,返回 null。
     * @param name    类的二进制名称 
     * @return    Class 对象,如果类没有被加载,则返回 null
     */
    protected final Class<?> findLoadedClass(String name) {
                // 如果名称为null或可能为有效二进制名称,则为true
        if (!checkName(name))
            return null;
        return findLoadedClass0(name);
    }
 
    private native final Class<?> findLoadedClass0(String name);
 
    /**
     * 设置类的签署者。应该在定义类后调用此方法。
     * @param c    Class 对象
     * @param signers    类的签署者
     */
    protected final void setSigners(Class<?> c, Object[] signers) {
        c.setSigners(signers);
    }
 
 
    // -- Resource --
 
    /**
     * 查找具有给定名称的资源。资源是可以通过类代码以与代码基无关的方式访问的一些数据(图像、声音、文本等)。
     *  资源名称是以 '/' 分隔的标识资源的路径名称。 此方法首先搜索资源的父类加载器;
     *  如果父类加载器为 null,则搜索的路径就是虚拟机的内置类加载器的路径。
     *  如果搜索失败,则此方法将调用 findResource(String) 来查找资源。
     * @param name    资源名称
     * @return    读取资源的 URL 对象;如果找不到该资源,或者调用者没有足够的权限获取该资源,则返回 null。
     */
    public URL getResource(String name) {
        URL url;
        // 搜索资源的父类加载器;
        if (parent != null) {
            url = parent.getResource(name);
        } else {
            // 如果父类加载器为 null,则搜索的路径就是虚拟机的内置类加载器的路径。
            url = getBootstrapResource(name);
        }
        if (url == null) {
            // 查找资源
            url = findResource(name);
        }
        return url;
    }
 
    /**
     * 查找所有给定名称的资源。资源是可以通过类代码以与代码基无关的方式访问的某些数据(图像、声音、文本等)。 
     * 资源名称是以 '/' 分隔的标识资源的路径名称。 
     * @param name    资源名称 
     * @return    资源的 URL 对象的枚举。如果找不到资源,则该枚举将为空。类加载器无权访问的资源不在此枚举中。 
     * @throws IOException
     */
    public Enumeration<URL> getResources(String name) throws IOException {
        @SuppressWarnings("unchecked")
        Enumeration<URL>[] tmp = (Enumeration<URL>[]) new Enumeration<?>[2];
        // 搜索资源的父类加载器;
        if (parent != null) {
            tmp[0] = parent.getResources(name);
        } else {
            // 如果父类加载器为 null,则搜索的路径就是虚拟机的内置类加载器的路径。
            tmp[0] = getBootstrapResources(name);
        }
     // 查找资源
        tmp[1] = findResources(name);
 
        return new CompoundEnumeration<>(tmp);
    }
 
    /**
     * 查找具有给定名称的资源。类加载器实现应该重写此方法,以指定从何处查找资源。
     * @param name    资源名称 
     * @return    用于读取资源的 URL 对象;如果无法找到资源,则返回 null
     */
    protected URL findResource(String name) {
        return null;
    }
 
    /**
     * 返回表示所有具有给定名称的资源的 URL 对象的枚举。类加载器实现应该重写此方法,以指定从何处加载资源。
     * @param name    资源名称
     * @return    资源的 URL 对象的枚举 
     * @throws IOException
     */
    protected Enumeration<URL> findResources(String name) throws IOException {
        return java.util.Collections.emptyEnumeration();
    }
 
    /**
     * 将调用者注册为并行的。
     * 注册成功当且仅当满足以下所有条件:
     * 1. 没有创建调用者的实例
     * 2. 调用者的所有超类(类对象除外)都被注册为并行的
     * 请注意,一旦类装入器被注册为具有并行能力,就无法将其更改回来。
     * @return 如果调用方成功注册为具有并行能力,则为true;如果调用方注册为具有并行能力,则为false。
     */
    @CallerSensitive
    protected static boolean registerAsParallelCapable() {
        Class<? extends ClassLoader> callerClass =
            Reflection.getCallerClass().asSubclass(ClassLoader.class);
        // 将给定的类装入器类型注册为并行capabale。
        return ParallelLoaders.register(callerClass);
    }
 
    /**
     * 从用来加载类的搜索路径中查找具有指定名称的资源。
     * 此方法通过系统类加载器(参见 getSystemClassLoader())来查找资源。
     * @param name    资源名称 
     * @return    用于读取资源的 URL 对象,如果找不到资源,则返回 null
     */
    public static URL getSystemResource(String name) {
        // 获取委托的系统类加载器。
        ClassLoader system = getSystemClassLoader();
        if (system == null) {
            // 获取虚拟机的内置类加载器。
            return getBootstrapResource(name);
        }
        // 查找具有给定名称的资源。
        return system.getResource(name);
    }
 
    /**
     * 从用来加载类的搜索路径中查找所有具有指定名称的资源。
     * 找到的资源作为 URL 对象的 Enumeration 返回。 
     * @param name    资源名称
     * @return    资源 URL 对象的枚举
     * @throws IOException
     */
    public static Enumeration<URL> getSystemResources(String name)
        throws IOException
    {
            // 获取委托的系统类加载器。
        ClassLoader system = getSystemClassLoader();
        if (system == null) {
                // 获取虚拟机的内置类加载器。
            return getBootstrapResources(name);
        }
         // 查找具有给定名称的资源。
        return system.getResources(name);
    }
 
    /**
     * 从VM的内置类加载器中查找资源。
     * @param name    资源名称
     * @return 用于读取资源的 URL 对象,如果找不到资源,则返回 null
     */
    private static URL getBootstrapResource(String name) {
        // 返回用于查找系统资源的URLClassPath。
        URLClassPath ucp = getBootstrapClassPath();
        Resource res = ucp.getResource(name);
        return res != null ? res.getURL() : null;
    }
 
    /**
     * 从VM的内置类加载器中查找资源。
     * @param name    资源名称
     * @return    资源 URL 对象的枚举
     * @throws IOException
     */
    private static Enumeration<URL> getBootstrapResources(String name)
        throws IOException
    {
        final Enumeration<Resource> e =
            getBootstrapClassPath().getResources(name);
        return new Enumeration<URL> () {
            public URL nextElement() {
                return e.nextElement().getURL();
            }
            public boolean hasMoreElements() {
                return e.hasMoreElements();
            }
        };
    }
 
    /**
     * 返回用于查找系统资源的URLClassPath。
     * @return
     */
    static URLClassPath getBootstrapClassPath() {
        return sun.misc.Launcher.getBootstrapClassPath();
    }
 
    /**
     * 返回读取指定资源的输入流。 
     * @param name    资源名称 
     * @return    用于读取资源的输入流,如果无法找到资源,则返回 null
     */
    public InputStream getResourceAsStream(String name) {
        // 查找具有给定名称的资源。
        URL url = getResource(name);
        try {
            return url != null ? url.openStream() : null;
        } catch (IOException e) {
            return null;
        }
    }
 
    /**
     * 从用来加载类的搜索路径打开具有指定名称的资源,以读取该资源。
     * @param name    资源名称 
     * @return    用于读取资源的输入流,如果无法找到资源,则返回 null
     */
    public static InputStream getSystemResourceAsStream(String name) {
        // 从用来加载类的搜索路径中查找具有指定名称的资源。
        URL url = getSystemResource(name);
        try {
            return url != null ? url.openStream() : null;
        } catch (IOException e) {
            return null;
        }
    }
 
 
    // -- Hierarchy --
 
    /**
     * 返回委托的父类加载器。一些实现可能使用 null 来表示引导类加载器。
     * 如果类加载器的父类加载器就是引导类加载器,则此方法将在这样的实现中返回 null。 
     * 如果存在安全管理器,且调用者的类加载器既不是 null,也不是此类加载器的祖先,
     * 那么此方法将使用 RuntimePermission("getClassLoader") 权限调用安全管理器的 checkPermission 方法,
     * 以检验是否允许访问该类的父类加载器。如果无此权限,则抛出 SecurityException 异常。 
     * @return
     */
    @CallerSensitive
    public final ClassLoader getParent() {
        if (parent == null)
            return null;
     // 获取系统安全接口
        SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            /*
             * 检查对父类加载器的访问,
             * 如果调用方的类加载器与此类加载器相同,执行权限检查。
             */
            checkClassLoaderPermission(parent, Reflection.getCallerClass());
        }
        return parent;
    }
 
    /**
     * 返回委托的系统类加载器。该加载器是新的 ClassLoader 实例的默认委托父类加载器,
     * 通常是用来启动应用程序的类加载器。 
     * 在运行时启动序列的早期首先调用此方法,这时会创建系统类加载器并将其设置为调用 Thread 的上下文类加载器。 
     * 默认的系统类加载器是此类的一个与实现有关的实例。 
     * 如果在第一次调用此方法时定义系统属性 "java.system.class.loader",
     * 那么该属性的值就是将作为系统类加载器返回的那个类的名称。
     * 该类是使用默认系统类加载器进行加载的,它必须定义一个公共的构造方法,
     * 此构造方法带有用作委托父类加载器的 ClassLoader 类型的单个参数。
     * 然后可以使用将默认系统类加载器用作参数的此构造方法创建一个实例。得到的类加载器被定义为系统类加载器。 
     * 如果存在安全管理器,且调用者的类加载器既不是 null,也不同于或不是系统类加载器的祖先,
     * 那么该方法将使用 RuntimePermission("getClassLoader") 权限调用安全管理器的 checkPermission 方法,
     * 以检验系统类加载器的访问权。如果无此权限,则抛出 SecurityException 异常。
     * @return    委托的系统 ClassLoader,如果没有这样的类加载器,则返回 null 
     */
    @CallerSensitive
    public static ClassLoader getSystemClassLoader() {
        // 创建系统类加载器
        initSystemClassLoader();
        if (scl == null) {
            return null;
        }
        // 获取系统安全接口
        SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            /*
             * 检查对父类加载器的访问,
             * 如果调用方的类加载器与此类加载器相同,执行权限检查。
             */
            checkClassLoaderPermission(scl, Reflection.getCallerClass());
        }
        return scl;
    }
    /**
     *  创建系统类加载器
     */
    private static synchronized void initSystemClassLoader() {
        if (!sclSet) {
            if (scl != null)
                throw new IllegalStateException("recursive invocation");
            sun.misc.Launcher l = sun.misc.Launcher.getLauncher();
            if (l != null) {
                Throwable oops = null;
                // 返回类加载器
                scl = l.getClassLoader();
                try {
                    // 启用特权,执行指定的 PrivilegedAction。
                    scl = AccessController.doPrivileged(
                        new SystemClassLoaderAction(scl));
                } catch (PrivilegedActionException pae) {
                    // 返回此异常的原因
                    oops = pae.getCause();
                    if (oops instanceof InvocationTargetException) {
                        oops = oops.getCause();
                    }
                }
                if (oops != null) {
                    if (oops instanceof Error) {
                        throw (Error) oops;
                    } else {
                        // 包装异常
                        throw new Error(oops);
                    }
                }
            }
            sclSet = true;
        }
    }
 
    /**
     * 如果指定的类加载器可以在该类加载器的委托链中找到,则返回true。
     * @param cl
     * @return
     */
    boolean isAncestor(ClassLoader cl) {
        ClassLoader acl = this;
        do {
            acl = acl.parent;
            if (cl == acl) {
                return true;
            }
        } while (acl != null);
        return false;
    }
 
    /**
     * 测试类加载器访问是否需要“getClassLoader”权限检查。
     * 类加载器'from'可以访问类加载器'to',如果类加载器'from'与类加载器'to'或'to'的祖先相同的话。
     * system domain中的类加载器可以访问任何类加载器。
     * @param from
     * @param to
     * @return
     */
    private static boolean needsClassLoaderPermissionCheck(ClassLoader from,
                                                           ClassLoader to)
    {
        if (from == to)
            return false;
 
        if (from == null)
            return false;
    // 如果指定的类加载器可以在该类加载器的委托链中找到,则返回true。
        return !to.isAncestor(from);
    }
 
    /**
     * 返回类加载器
     * @param caller
     * @return
     */
    static ClassLoader getClassLoader(Class<?> caller) {
        // 如果VM请求它,它可以是null
        if (caller == null) {
            return null;
        }
        // 绕过安全检查,因为这是包私有的
        return caller.getClassLoader0();
    }
 
    /**
     * 如果调用者的类加载器不为空,且调用者的类加载器与给定cl参数不相同或不是其祖先,
     * 则检查运行时权限(“getClassLoader”)权限。
     * @param cl
     * @param caller
     */
    static void checkClassLoaderPermission(ClassLoader cl, Class<?> caller) {
        // 获取系统安全接口
        SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            //如果VM正在请求调用者,则调用者可以为空
            ClassLoader ccl = getClassLoader(caller);
            if (needsClassLoaderPermissionCheck(ccl, cl)) {
                sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
            }
        }
    }
 
    /*
     * 系统的类加载器
     *  @GuardedBy (“ClassLoader.class”)
     */
    private static ClassLoader scl;
 
    /*
     * 一旦系统类加载器被设置为true
     * @GuardedBy (“ClassLoader.class”)
     */
    private static boolean sclSet;
 
 
    // -- Package --
 
    /**
     * 根据 name 在此 ClassLoader 中定义包。这允许类加载器定义用于它们的类的包。
     * 包必须在定义类之前创建,包名在类加载器中必须惟一,并且一旦创建就不能重新定义或更改。
     * @param name    包名
     * @param specTitle    规范标题
     * @param specVersion    规范版本
     * @param specVendor    规范供应商
     * @param implTitle    实现标题
     * @param implVersion    实现版本
     * @param implVendor    实现供应商
     * @param sealBase    如果不为 null,那么将此包对于给定代码源 URL 对象是密封的。否则,不密封此包。 
     * @return    新定义的 Package 对象 
     * @throws IllegalArgumentException
     */
    protected Package definePackage(String name, String specTitle,
                                    String specVersion, String specVendor,
                                    String implTitle, String implVersion,
                                    String implVendor, URL sealBase)
        throws IllegalArgumentException
    {
        synchronized (packages) {
        // 获取由此类加载器或其任何祖先所定义的 Package
            Package pkg = getPackage(name);
            if (pkg != null) {
                throw new IllegalArgumentException(name);
            }
            pkg = new Package(name, specTitle, specVersion, specVendor,
                              implTitle, implVersion, implVendor,
                              sealBase, this);
            packages.put(name, pkg);
            return pkg;
        }
    }
 
    /**
     * 返回由此类加载器或其任何祖先所定义的 Package。
     * @param name    包名
     * @return    与给定名称相对应的 Package;如果没有这样的包,则返回 null
     */
    protected Package getPackage(String name) {
        Package pkg;
        synchronized (packages) {
            pkg = packages.get(name);
        }
        if (pkg == null) {
            if (parent != null) {
                // 获取祖先所定义的 Package
                pkg = parent.getPackage(name);
            } else {
                // 返回指定名称的已加载系统包。
                pkg = Package.getSystemPackage(name);
            }
            if (pkg != null) {
                synchronized (packages) {
                    Package pkg2 = packages.get(name);
                    if (pkg2 == null) {
                        packages.put(name, pkg);
                    } else {
                        pkg = pkg2;
                    }
                }
            }
        }
        return pkg;
    }
 
    /**
     * 返回此类加载器及其祖先所定义的所有 Package
     * @return
     */
    protected Package[] getPackages() {
        Map<String, Package> map;
        synchronized (packages) {
            map = new HashMap<>(packages);
        }
        Package[] pkgs;
        if (parent != null) {
            // 返回祖先所定义的所有 Package
            pkgs = parent.getPackages();
        } else {
            // 返回已加载系统包的数组。
            pkgs = Package.getSystemPackages();
        }
        if (pkgs != null) {
            for (int i = 0; i < pkgs.length; i++) {
                String pkgName = pkgs[i].getName();
                if (map.get(pkgName) == null) {
                    map.put(pkgName, pkgs[i]);
                }
            }
        }
        return map.values().toArray(new Package[map.size()]);
    }
 
 
    // -- Native library access --
 
    /**
     * 返回本机库的绝对路径名。虚拟机 (VM) 调用此方法来查找那些属于利用此类加载器加载的类的本机库。
     * 如果此方法返回 null,则虚拟机沿指定为 "java.library.path" 属性的路径搜索该库。
     * @param libname    库名称
     * @return    本机库的绝对路径
     */
    protected String findLibrary(String libname) {
        return null;
    }
 
    /**
     * 内部类NativeLibrary表示加载的本机库实例。
     * 每个类加载器在私有字段nativeLibraries中包含一个已加载本机库的向量。
     * 加载到系统中的本机库被输入到systemNativeLibraries vector。
     * 
     * 每个本机库都需要特定版本的JNI。
     * 这由私有的JNI Version字段表示。
     * 这个字段是VM在加载库时设置的,
     * 并由VM用于将正确版本的JNI传递给本机方法。
     */
    static class NativeLibrary {
        // 本机库的不透明句柄,在本机代码中使用。
        long handle;
        // 本机库需要的JNI环境版本。
        private int jniVersion;
        // 加载库的类还指示此本机库所属的加载器。
        private final Class<?> fromClass;
        //本机库的规范化名称。或静态库名
        String name;
        // 指示本机库是否链接到VM
        boolean isBuiltin;
        // 指示是否加载本机库
        boolean loaded;
        native void load(String name, boolean isBuiltin);
 
        native long find(String name);
        native void unload(String name, boolean isBuiltin);
 
        public NativeLibrary(Class<?> fromClass, String name, boolean isBuiltin) {
            this.name = name;
            this.fromClass = fromClass;
            this.isBuiltin = isBuiltin;
        }
 
        protected void finalize() {
            synchronized (loadedLibraryNames) {
                if (fromClass.getClassLoader() != null && loaded) {
                    /* 删除本机库名称 */
                    int size = loadedLibraryNames.size();
                    for (int i = 0; i < size; i++) {
                        if (name.equals(loadedLibraryNames.elementAt(i))) {
                            loadedLibraryNames.removeElementAt(i);
                            break;
                        }
                    }
                    /* 卸载库。 */
                    ClassLoader.nativeLibraryContext.push(this);
                    try {
                        unload(name, isBuiltin);
                    } finally {
                        ClassLoader.nativeLibraryContext.pop();
                    }
                }
            }
        }
        // 在VM中调用,以确定JNI_Load/JNI_Unload中的上下文类
        static Class<?> getFromClass() {
            return ClassLoader.nativeLibraryContext.peek().fromClass;
        }
    }
 
    // 我们加载的所有本机库名称。
    private static Vector<String> loadedLibraryNames = new Vector<>();
 
    // 属于系统类的本机库。
    private static Vector<NativeLibrary> systemNativeLibraries
        = new Vector<>();
 
    // 与类装载器关联的本机库。
    private Vector<NativeLibrary> nativeLibraries = new Vector<>();
 
    // 正在加载/卸载本机库。
    private static Stack<NativeLibrary> nativeLibraryContext = new Stack<>();
 
    // 路径搜索库
    private static String usr_paths[];
    private static String sys_paths[];
    /**
     * 初始化库路径
     * @param propname
     * @return
     */
    private static String[] initializePath(String propname) {
        // 获取指定键指示的系统属性
        String ldpath = System.getProperty(propname, "");
        String ps = File.pathSeparator;
        int ldlen = ldpath.length();
        int i, j, n;
        // 计算路径中的分隔符
        i = ldpath.indexOf(ps);
        n = 0;
        while (i >= 0) {
            n++;
            i = ldpath.indexOf(ps, i + 1);
        }
 
        // 分配路径数组- n:'s = n + 1路径元素
        String[] paths = new String[n + 1];
 
        // 用ldpath中的路径填充数组
        n = i = 0;
        j = ldpath.indexOf(ps);
        while (j >= 0) {
            if (j - i > 0) {
                paths[n++] = ldpath.substring(i, j);
            } else if (j - i == 0) {
                paths[n++] = ".";
            }
            i = j + 1;
            j = ldpath.indexOf(ps, i);
        }
        paths[n] = ldpath.substring(i, ldlen);
        return paths;
    }
 
    /**
     * 在java.lang中调用。运行时类来实现load和loadLibrary。
     * @param fromClass
     * @param name
     * @param isAbsolute
     */
    static void loadLibrary(Class<?> fromClass, String name,
                            boolean isAbsolute) {
        ClassLoader loader =
            (fromClass == null) ? null : fromClass.getClassLoader();
        if (sys_paths == null) {
            usr_paths = initializePath("java.library.path");
            sys_paths = initializePath("sun.boot.library.path");
        }
        if (isAbsolute) {
            if (loadLibrary0(fromClass, new File(name))) {
                return;
            }
            throw new UnsatisfiedLinkError("Can't load library: " + name);
        }
        if (loader != null) {
            // 返回本机库的绝对路径名。
            String libfilename = loader.findLibrary(name);
            if (libfilename != null) {
                File libfile = new File(libfilename);
        // 测试此抽象路径名是否为绝对路径名。
                if (!libfile.isAbsolute()) {
                    throw new UnsatisfiedLinkError(
    "ClassLoader.findLibrary failed to return an absolute path: " + libfilename);
                }
                if (loadLibrary0(fromClass, libfile)) {
                    return;
                }
                throw new UnsatisfiedLinkError("Can't load " + libfilename);
            }
        }
        for (int i = 0 ; i < sys_paths.length ; i++) {
            // 加载由 libname 参数指定的系统库。
            File libfile = new File(sys_paths[i], System.mapLibraryName(name));
            if (loadLibrary0(fromClass, libfile)) {
                return;
            }
            libfile = ClassLoaderHelper.mapAlternativeName(libfile);
            if (libfile != null && loadLibrary0(fromClass, libfile)) {
                return;
            }
        }
        if (loader != null) {
            for (int i = 0 ; i < usr_paths.length ; i++) {
            // 加载由 libname 参数指定的用户库。
                File libfile = new File(usr_paths[i],
                                        System.mapLibraryName(name));
                if (loadLibrary0(fromClass, libfile)) {
                    return;
                }
        // 返回给定文件的备用路径名
                libfile = ClassLoaderHelper.mapAlternativeName(libfile);
                if (libfile != null && loadLibrary0(fromClass, libfile)) {
                    return;
                }
            }
        }
        // 失败
        throw new UnsatisfiedLinkError("no " + name + " in java.library.path");
    }
 
    private static native String findBuiltinLib(String name);
 
    private static boolean loadLibrary0(Class<?> fromClass, final File file) {
        // 检查是否试图访问静态库
        String name = findBuiltinLib(file.getName());
        boolean isBuiltin = (name != null);
        if (!isBuiltin) {
            boolean exists = AccessController.doPrivileged(
                new PrivilegedAction<Object>() {
                    public Object run() {
                        return file.exists() ? Boolean.TRUE : null;
                    }})
                != null;
            if (!exists) {
                return false;
            }
            try {
                // 返回此抽象路径名的规范形式
                name = file.getCanonicalPath();
            } catch (IOException e) {
                return false;
            }
        }
        ClassLoader loader =
            (fromClass == null) ? null : fromClass.getClassLoader();
        Vector<NativeLibrary> libs =
            loader != null ? loader.nativeLibraries : systemNativeLibraries;
        synchronized (libs) {
            int size = libs.size();
            for (int i = 0; i < size; i++) {
                NativeLibrary lib = libs.elementAt(i);
                if (name.equals(lib.name)) {
                    return true;
                }
            }
 
            synchronized (loadedLibraryNames) {
                if (loadedLibraryNames.contains(name)) {
                    throw new UnsatisfiedLinkError
                        ("Native Library " +
                         name +
                         " already loaded in another classloader");
                }
                /* 如果正在加载库(必须是同样的线程,因为运行时。加载和运行时。loadLibrary同步)。
                 * 原因是JNI_OnLoad函数可能导致另一个loadLibrary调用。
                 *
                 * 因此,我们可以使用静态堆栈来保存正在加载的库列表。
                 *
                 * 如果库有一个挂起的加载操作,
                 * 我们立即回报成功;否则,我们会产生UnsatisfiedLinkError。
                 */
                int n = nativeLibraryContext.size();
                for (int i = 0; i < n; i++) {
                    NativeLibrary lib = nativeLibraryContext.elementAt(i);
                    if (name.equals(lib.name)) {
                        if (loader == lib.fromClass.getClassLoader()) {
                            return true;
                        } else {
                            throw new UnsatisfiedLinkError
                                ("Native Library " +
                                 name +
                                 " is being loaded in another classloader");
                        }
                    }
                }
                NativeLibrary lib = new NativeLibrary(fromClass, name, isBuiltin);
                nativeLibraryContext.push(lib);
                try {
                    lib.load(name, isBuiltin);
                } finally {
                    nativeLibraryContext.pop();
                }
                if (lib.loaded) {
                    loadedLibraryNames.addElement(name);
                    libs.addElement(lib);
                    return true;
                }
                return false;
            }
        }
    }
 
    /**
     * 在VM类链接代码中调用。
     * @param loader
     * @param name
     * @return
     */
    static long findNative(ClassLoader loader, String name) {
        Vector<NativeLibrary> libs =
            loader != null ? loader.nativeLibraries : systemNativeLibraries;
        synchronized (libs) {
            int size = libs.size();
            for (int i = 0; i < size; i++) {
                NativeLibrary lib = libs.elementAt(i);
                long entry = lib.find(name);
                if (entry != 0)
                    return entry;
            }
        }
        return 0;
    }
 
 
    // -- Assertion management --
    // ssertion管理
    final Object assertionLock;
 
    /*
     * 断言检查的默认切换。
     * @GuardedBy (“assertionLock”)
     */
    private boolean defaultAssertionStatus = false;
 
    /*
     * 将字符串packageName映射到布尔包的默认断言状态。
     * 如果该字段为null,则我们将断言状态查询委托给VM,即没有调用这个类加载器的断言状态修改方法。
     * @GuardedBy (“assertionLock”)
     */
    private Map<String, Boolean> packageAssertionStatus = null;
 
    /*
     * 如果该字段为空,则我们将断言状态查询委托给VM,即没有调用这个类加载器的断言状态修改方法。
     * @GuardedBy (“assertionLock”)
     */
    Map<String, Boolean> classAssertionStatus = null;
 
    /**
     * 设置此类加载器的默认断言状态。
     * 此设置确定由此类加载器加载并在将来初始化的类在默认情况下是启用还是禁用断言。
     * 通过调用 setPackageAssertionStatus(String, boolean) 或 setClassAssertionStatus(String, boolean),
     * 在每个包或每个类上重写此设置。
     * @param enabled    如果由此类加载器加载的类将默认为启用断言,则该参数为 true;如果默认为禁用断言,则该参数为 false。
     */
    public void setDefaultAssertionStatus(boolean enabled) {
        synchronized (assertionLock) {
            if (classAssertionStatus == null)
                // 使用VM提供的信息设置断言。
                initializeJavaAssertionMaps();
 
            defaultAssertionStatus = enabled;
        }
    }
 
    /**
     * 为指定包设置默认断言状态。包的默认断言状态确定了以后初始化属于指定包或其子包的类的断言状态。 
     * 名为 p 的包的子包是所有名称以 "p." 开头的包。
     * 例如,javax.swing.text 是 javax.swing 的子包,java.util 和 java.lang.reflect 是 java 的子包。 
     * 如果默认情况下多个包可应用于一个给定类,则默认与最特殊的包相关的包拥有高于其他包的优先级。
     * 例如,如果 javax.lang 和 javax.lang.reflect 都具有与之相关的默认包,
     * 则将后者应用于 javax.lang.reflect 中的类。 
     * 包的优先级默认情况下高于类加载器的默认断言状态,
     * 并且可以通过调用 setClassAssertionStatus(String, boolean) 在每个类的基础上进行重写。 
     * @param packageName    要设置其默认包断言状态的包名。
     * @param enabled    如果由此类加载器加载并属于指定包或其子包的类在默认情况下启用断言,
     *                     则该参数为 true;如果在默认情况下禁用断言,则该参数为 false。
     */
    public void setPackageAssertionStatus(String packageName,
                                          boolean enabled) {
        synchronized (assertionLock) {
            if (packageAssertionStatus == null)
        // 使用VM提供的信息设置断言。
                initializeJavaAssertionMaps();
 
            packageAssertionStatus.put(packageName, enabled);
        }
    }
 
    /**
     * 设置在此类加载器及其包含的嵌套类中指定的最高层类所需的断言状态。
     * 该设置的优先级高于类加载器的默认断言状态以及可用的任何包的默认值。
     * 如果已经初始化指定类,则此方法无效。(初始化类后,其断言状态无法再改变。) 
     * 如果指定类不是最高层的类,则此调用对任何类的实际断言都无效。
     * @param className    将要设置其断言状态的最高层类的完全限定类名。
     * @param enabled    如果指定类在初始化时启用断言,则该参数为true;如果该类禁用断言,则该参数为false。
     */
    public void setClassAssertionStatus(String className, boolean enabled) {
        synchronized (assertionLock) {
            if (classAssertionStatus == null)
                initializeJavaAssertionMaps();
 
            classAssertionStatus.put(className, enabled);
        }
    }
 
    /**
     * 将此类加载器的默认断言状态设置为 false,并放弃与此类加载器关联的所有默认包或类断言状态设置。
     * 提供此方法可以让类加载器忽略任何命令行或持久断言状态设置,并且“无不良记录”。 
     */
    public void clearAssertionStatus() {
        /*
         * 无论“Java断言映射”是否初始化,
         * 将它们设置为空映射,有效地忽略任何当前设置。
         */
        synchronized (assertionLock) {
            classAssertionStatus = new HashMap<>();
            packageAssertionStatus = new HashMap<>();
            defaultAssertionStatus = false;
        }
    }
 
    /**
     * 返回将分配给指定类的断言状态(如果在调用此方法时初始化该类)。
     * 如果指定的类已经设置了断言状态,则返回最近的设置;
     * 否则,如果任何包的默认断言状态属于这个类,
     * 返回最特定的相关包默认断言状态的最新设置;
     * 否则,将返回这个类装入器的默认断言状态。
     * @param className    正在查询所需断言状态的类的完全限定类名
     * @return    指定类的所需断言状态
     */
    boolean desiredAssertionStatus(String className) {
        synchronized (assertionLock) {
            // assert classAssertionStatus   != null;
            // assert packageAssertionStatus != null;
 
            // 检查类entry
            Boolean result = classAssertionStatus.get(className);
            if (result != null)
                return result.booleanValue();
 
            // 检查大多数特定的包entry
            int dotIndex = className.lastIndexOf(".");
            if (dotIndex < 0) { // 默认 package
                result = packageAssertionStatus.get(null);
                if (result != null)
                    return result.booleanValue();
            }
            while(dotIndex > 0) {
                className = className.substring(0, dotIndex);
                result = packageAssertionStatus.get(className);
                if (result != null)
                    return result.booleanValue();
                dotIndex = className.lastIndexOf(".", dotIndex-1);
            }
 
            // 返回类加载器默认值
            return defaultAssertionStatus;
        }
    }
 
    /**
     * 使用VM提供的信息设置断言。
     * 注意:应该只在同步块中调用
     */
    private void initializeJavaAssertionMaps() {
        // assert Thread.holdsLock(assertionLock);
 
        classAssertionStatus = new HashMap<>();
        packageAssertionStatus = new HashMap<>();
        // 从VM检索断言指令。
        AssertionStatusDirectives directives = retrieveDirectives();
        // 类断言状态处理
        for(int i = 0; i < directives.classes.length; i++)
            classAssertionStatus.put(directives.classes[i],
                                     directives.classEnabled[i]);
        // 包断言状态处理
        for(int i = 0; i < directives.packages.length; i++)
            packageAssertionStatus.put(directives.packages[i],
                                       directives.packageEnabled[i]);
        // 默认断言状态处理
        defaultAssertionStatus = directives.deflt;
    }
 
        // 从VM检索断言指令。
    private static native AssertionStatusDirectives retrieveDirectives();
}
 
 
class SystemClassLoaderAction
    implements PrivilegedExceptionAction<ClassLoader> {
    private ClassLoader parent;
 
    SystemClassLoaderAction(ClassLoader parent) {
        this.parent = parent;
    }
 
    public ClassLoader run() throws Exception {
        String cls = System.getProperty("java.system.class.loader");
        if (cls == null) {
            return parent;
        }
 
        Constructor<?> ctor = Class.forName(cls, true, parent)
            .getDeclaredConstructor(new Class<?>[] { ClassLoader.class });
        ClassLoader sys = (ClassLoader) ctor.newInstance(
            new Object[] { parent });
        Thread.currentThread().setContextClassLoader(sys);
        return sys;
    }
}
参考文档:JDK 1.6

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值