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

可能重复:
使用ClassLoader和Class.forName加载类之间的差异

AFAIK, java提供了两种方法来从其名称初始化类。

  • 公共静态类forName(字符串className)抛出ClassNotFoundException

  • public static Class forName(String name,boolean initialize,ClassLoader loader)会抛出ClassNotFoundException

  • ClassLoader

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

  • 已知的事情是在forName方法中,我们可以指定initialize的标志为false ,这将跳过一些静态的东西来初始化这个类。 但是还有什么? 我应该如何正确使用它们?

    最好你可以展示一些很好的例子。

    谢谢!

    更新:

    在提出问题后,我做了一些简单的classLoader测试。

    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));
    

    结果是

    真的,真的,假的,真正的

    UPDATE

    这是我的答案
    loadClass(String name)和loadClass(String name,boolean resolve)之间的区别


    考虑这个代码

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

    最基本的API是ClassLoader.loadClass(String name, boolean resolve)

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

    如果resolve为真,它也会尝试加载由X引用的所有类。 在这种情况下, Y也会被加载。 如果resolve错误,则此时不会加载Y

    似乎没有任何理由resolve=true 。 如果没有人调用X.bar() ,那么Y永远不会被需要,为什么我们现在应该加载它? 如果Y丢失或损坏,我们会尝试加载X ,这是完全没有必要的。

    有趣的是,这种方法是protected ,因此调用它并不容易。

    另一种方法loadClass(name)简单地调用loadClass(name,false) 。 它是公开的,它需要resolve=false的明智选择。 所以这正是开发人员所需要的。

    ClassLoader只加载类,它不初始化类。 我们可以检查类的元数据,例如它的超类,它的注释,它的方法和字段等,而不触发静态的初始化执行。 这个事实对于框架非常重要。

    现在, Class.forName

    基本上, Class.forName(String name, boolean initialize, ClassLoader loader)调用loader.loadClass(name) 。 如果initialize=true ,则该类将被初始化 - 在X示例中,我们将看到"init class X..."打印出来。

    Class.forName(name)forName(name, true, currentLoader)

    现在,为什么有人想在这个时候初始化这个类? 如果班级只在必要时才初始化,会不会更好? 一个着名的用例是JDBC初始化:

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

    约定是,JDBC驱动程序类将其自身注册到其静态初始化程序中。 上述代码将触发静态初始化,使驱动程序可供后续使用。

    从今天的角度来看,这个设计非常奇怪。 我们通常不依赖于静态初始化器。 所以initialize=true没有太大的理由,应该避免使用Class.forName(name)

    “类文字”将返回该类,而不初始化它

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

    现在,什么是“currentLoader”? 它是当前类的类加载器

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

    当第一次调用X.bar()时,需要一个“Y”类。 发生的事情大致是这样

    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)将尝试使用指定的类加载器加载该类。 Class.forName(String name)将尝试使用默认系统类加载器层次结构加载该类。

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

    上一篇: What's the difference between ClassLoader.load(name) and Class.forName(name)

    下一篇: Debugging a ClassNotFoundException