美文网首页
Java之ClassLoader.loadClass()与Cla

Java之ClassLoader.loadClass()与Cla

作者: zhglance | 来源:发表于2020-02-04 14:49 被阅读0次

    在JVM中,类装载器把一个类装入JVM中,需要 装载、链接和初始化 三个步骤:

    1.装载:

    加载.class字节码文件,将.class的静态存储结构转化为方法区的运行时数据结构,生成Class对象;

    2.链接:

    校验:检查Class对象二进制数据的正确性,并保证JVM的安全;
    准备:给类的静态变量分配并初始化存储空间,并设置类变量初始值;
    解析:将常量池内的符号引用转成直接引用。

    3.初始化:

    激活类的静态变量的初始化Java代码和静态Java代码块,即类执行构造器<clini>()方法的过程。

    4.Class.forName

    Class.forName(String name)方法,其实调用的方法是Class.forName(String name, boolean initialize, ClassLoader loader),Class.forName(className)装载的Class已经被实例化, initialize=true表示加载Class后执行初始化 。

    其中:forName0方法为C++编写的native方法。

    源码:

        /**
         * Returns the {@code Class} object associated with the class or
         * interface with the given string name.  Invoking this method is
         * equivalent to:
         *
         * <blockquote>
         *  {@code Class.forName(className, true, currentLoader)}
         * </blockquote>
         *
         * where {@code currentLoader} denotes the defining class loader of
         * the current class.
         *
         * <p> For example, the following code fragment returns the
         * runtime {@code Class} descriptor for the class named
         * {@code java.lang.Thread}:
         *
         * <blockquote>
         *   {@code Class t = Class.forName("java.lang.Thread")}
         * </blockquote>
         * <p>
         * A call to {@code forName("X")} causes the class named
         * {@code X} to be initialized.
         *
         * @param      className   the fully qualified name of the desired class.
         * @return     the {@code Class} object for the class with the
         *             specified name.
         * @exception LinkageError if the linkage fails
         * @exception ExceptionInInitializerError if the initialization provoked
         *            by this method fails
         * @exception ClassNotFoundException if the class cannot be located
         */
        @CallerSensitive
        public static Class<?> forName(String className)
                    throws ClassNotFoundException {
            Class<?> caller = Reflection.getCallerClass();
            return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
        }
    
    
        /**
         * Returns the {@code Class} object associated with the class or
         * interface with the given string name, using the given class loader.
         * Given the fully qualified name for a class or interface (in the same
         * format returned by {@code getName}) this method attempts to
         * locate, load, and link the class or interface.  The specified class
         * loader is used to load the class or interface.  If the parameter
         * {@code loader} is null, the class is loaded through the bootstrap
         * class loader.  The class is initialized only if the
         * {@code initialize} parameter is {@code true} and if it has
         * not been initialized earlier.
         *
         * <p> If {@code name} denotes a primitive type or void, an attempt
         * will be made to locate a user-defined class in the unnamed package whose
         * name is {@code name}. Therefore, this method cannot be used to
         * obtain any of the {@code Class} objects representing primitive
         * types or void.
         *
         * <p> If {@code name} denotes an array class, the component type of
         * the array class is loaded but not initialized.
         *
         * <p> For example, in an instance method the expression:
         *
         * <blockquote>
         *  {@code Class.forName("Foo")}
         * </blockquote>
         *
         * is equivalent to:
         *
         * <blockquote>
         *  {@code Class.forName("Foo", true, this.getClass().getClassLoader())}
         * </blockquote>
         *
         * Note that this method throws errors related to loading, linking or
         * initializing as specified in Sections 12.2, 12.3 and 12.4 of <em>The
         * Java Language Specification</em>.
         * Note that this method does not check whether the requested class
         * is accessible to its caller.
         *
         * <p> If the {@code loader} is {@code null}, and a security
         * manager is present, and the caller's class loader is not null, then this
         * method calls the security manager's {@code checkPermission} method
         * with a {@code RuntimePermission("getClassLoader")} permission to
         * ensure it's ok to access the bootstrap class loader.
         *
         * @param name       fully qualified name of the desired class
         * @param initialize if {@code true} the class will be initialized.
         *                   See Section 12.4 of <em>The Java Language Specification</em>.
         * @param loader     class loader from which the class must be loaded
         * @return           class object representing the desired class
         *
         * @exception LinkageError if the linkage fails
         * @exception ExceptionInInitializerError if the initialization provoked
         *            by this method fails
         * @exception ClassNotFoundException if the class cannot be located by
         *            the specified class loader
         *
         * @see       java.lang.Class#forName(String)
         * @see       java.lang.ClassLoader
         * @since     1.2
         */
        @CallerSensitive
        public static Class<?> forName(String name, boolean initialize,
                                       ClassLoader loader)
            throws ClassNotFoundException
        {
            Class<?> caller = null;
            SecurityManager sm = System.getSecurityManager();
            if (sm != null) {
                // Reflective call to get caller class is only needed if a security manager
                // is present.  Avoid the overhead of making this call otherwise.
                caller = Reflection.getCallerClass();
                if (sun.misc.VM.isSystemDomainLoader(loader)) {
                    ClassLoader ccl = ClassLoader.getClassLoader(caller);
                    if (!sun.misc.VM.isSystemDomainLoader(ccl)) {
                        sm.checkPermission(
                            SecurityConstants.GET_CLASSLOADER_PERMISSION);
                    }
                }
            }
            return forName0(name, initialize, loader, caller);
        }
    

    5.ClassLoader.loadClass

    ClassLoader.loadClass(String name)方法,其实他调用的方法是ClassLoader.loadClass((String name, boolean resolve),resolve=false表示被装载后不进行链接。

    源码:

        // -- Class --
    
        /**
         * Loads the class with the specified <a href="#name">binary name</a>.
         * This method searches for classes in the same manner as the {@link
         * #loadClass(String, boolean)} method.  It is invoked by the Java virtual
         * machine to resolve class references.  Invoking this method is equivalent
         * to invoking {@link #loadClass(String, boolean) <tt>loadClass(name,
         * false)</tt>}.
         *
         * @param  name
         *         The <a href="#name">binary name</a> of the class
         *
         * @return  The resulting <tt>Class</tt> object
         *
         * @throws  ClassNotFoundException
         *          If the class was not found
         */
        public Class<?> loadClass(String name) throws ClassNotFoundException {
            return loadClass(name, false);
        }
    
        /**
         * Loads the class with the specified <a href="#name">binary name</a>.  The
         * default implementation of this method searches for classes in the
         * following order:
         *
         * <ol>
         *
         *   <li><p> Invoke {@link #findLoadedClass(String)} to check if the class
         *   has already been loaded.  </p></li>
         *
         *   <li><p> Invoke the {@link #loadClass(String) <tt>loadClass</tt>} method
         *   on the parent class loader.  If the parent is <tt>null</tt> the class
         *   loader built-in to the virtual machine is used, instead.  </p></li>
         *
         *   <li><p> Invoke the {@link #findClass(String)} method to find the
         *   class.  </p></li>
         *
         * </ol>
         *
         * <p> If the class was found using the above steps, and the
         * <tt>resolve</tt> flag is true, this method will then invoke the {@link
         * #resolveClass(Class)} method on the resulting <tt>Class</tt> object.
         *
         * <p> Subclasses of <tt>ClassLoader</tt> are encouraged to override {@link
         * #findClass(String)}, rather than this method.  </p>
         *
         * <p> Unless overridden, this method synchronizes on the result of
         * {@link #getClassLoadingLock <tt>getClassLoadingLock</tt>} method
         * during the entire class loading process.
         *
         * @param  name
         *         The <a href="#name">binary name</a> of the class
         *
         * @param  resolve
         *         If <tt>true</tt> then resolve the class
         *
         * @return  The resulting <tt>Class</tt> object
         *
         * @throws  ClassNotFoundException
         *          If the class could not be found
         */
        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;
            }
        }
    

    相关文章

      网友评论

          本文标题:Java之ClassLoader.loadClass()与Cla

          本文链接:https://www.haomeiwen.com/subject/sohrxhtx.html