What's the difference between ClassLoader.load(name) and Class.forName(name)

Possible Duplicate:
Difference betweeen Loading a class using ClassLoader and Class.forName

AFAIK, two ways are provided in java to init a class from its name.

  • Class

  • public static Class forName(String className) throws ClassNotFoundException

  • public static Class forName(String name, boolean initialize, ClassLoader loader) throws ClassNotFoundException

  • ClassLoader :

    public Class loadClass(String name) throws ClassNotFoundException { return loadClass(name, false); }

  • The known thing is in forName method, we can specify the flag of initialize to be false ,this will skip some static things to be initialized for this class. But what's else? And how should I use them correctly?

    It's better you can show some good examples.

    Thanks!

    UPDATE:

    After raised question,I made some simple classLoader test.

    ClassLoader cls = ClassLoader.getSystemClassLoader(); 
            Class someClass = cls.loadClass("Test");         
            Class someClass0= Class.forName("Test");        
            Class someClass1= Class.forName("Test",false,cls);
    
    
            URL[] urls = new URL[] {new File("bin/").toURL()}; 
            ClassLoader cls2 = new URLClassLoader(urls, null); 
            Class someClass2 = cls2.loadClass("Test");         
    
            ClassLoader cls3 = new URLClassLoader(urls, cls); 
            Class someClass3 = cls3.loadClass("Test");         
    
           System.out.println(someClass.equals(someClass0));       
           System.out.println(someClass.equals(someClass1));
           System.out.println(someClass.equals(someClass2)); 
           System.out.println(someClass.equals(someClass3));
    

    The result is

    true,true,false,true

    UPDATE

    Here is my answer about
    Difference between loadClass(String name) and loadClass(String name, boolean resolve)


    Consider this code

    class X
    {
        static{   System.out.println("init class X..."); }
    
        int foo(){ return 1; }
    
        Y bar(){ return new Y(); }
    }
    

    The most basic API is ClassLoader.loadClass(String name, boolean resolve)

        Class classX = classLoader.loadClass("X", resolve);
    

    If resolve is true, it will also try to load all classes referenced by X . In this case, Y will also be loaded. If resolve is false, Y will not be loaded at this point.

    There doesn't seems to be any good reason for resolve=true . If nobody calls X.bar() , Y will never be needed, why should we load it at this point? And if Y is missing or corrupt, we'll get an error trying to load X , which is totally unnecessary.

    Interestingly, this method is protected , so it's not easy to invoke it.

    Another method loadClass(name) simply calls loadClass(name,false) . It's public, and it takes the sensible choice of resolve=false . So it is exactly what's needed by developers.

    ClassLoader only loads classes, it does not initialize classes. We can inspect the class metadata, eg its super class, its annotations, its methods and fields, etc. without triggering the static initialization execution. This fact is very important for frameworks.

    Now, Class.forName

    Basically, Class.forName(String name, boolean initialize, ClassLoader loader) calls loader.loadClass(name) . And if initialize=true , the class is initialized - in the X example, we'll see "init class X..." printed.

    Class.forName(name) is the same as forName(name, true, currentLoader) .

    Now, why would anyone want to initialize the class at this point? Wouldn't it be better if the class is initialized only when necessary? A famous use case is JDBC initializing:

        Class.forName("com.mysql.jdbc.Driver");
    

    The convention is, a JDBC driver class registers itself in its static initializer. The above code will trigger the static initialization, making the driver available for subsequent uses.

    From today's point of view, that design is really odd. We usually don't rely on static initializers. So there isn't much justification for initialize=true , and Class.forName(name) should be avoided.

    A "class literal" will return the class, without initializing it

        Class c = com.mysql.jdbc.Driver.class;
        // actually compiled to
        Class c = Class.forName("com.mysql.jdbc.Driver", false, currentLoader);
    

    Now, what the heck is the "currentLoader"? It is the class loader of the current class

    class A
    {
        void foo()
        {
            currenLoader == THIS_A_CLASS.getClassLoader()
        }
    }
    

    When X.bar() is invoked for the first time, a "Y" class is needed. what's happening is roughly

    class X
        bar()
            // new Y();
    
            Class classY = currentLoader.loadClass("Y");
            Constructor cst = classY.getConstructor();
    
            // next line will initialize Y (if not yet)
            // creating an instance of a class requires it be initialized
            Object y = cst.newInstance();
    

    ClassLoader.loadClass(String name) will attempt to load the class using the specified classloader. Class.forName(String name) will attempt to load the class using the default system classloader hierarchy.

    链接地址: http://www.djcxy.com/p/58272.html

    上一篇: 任何方式从字节数组创建一个URL?

    下一篇: ClassLoader.load(name)和Class.forName(name)之间的区别是什么?