2011-07-10 160 views
2

可能重复的区别:
Difference betweeen Loading a class using ClassLoader and Class.forName什么ClassLoader.load(名称)和的Class.forName(名称)

据我所知,在的Java提供了两种方法来初始化一个名字的类。

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

  • 公共静态类的forName(字符串 名,布尔初始化,类加载器 装载机)抛出的ClassNotFoundException

  • 的ClassLoader

    公共类的loadClass(字符串 名)抛出的ClassNotFoundException { 回报的loadClass(姓名,假); }

已知的是在的forName方法,我们可以指定初始化的标志是,这将跳过某些该类被初始化静态的东西。但是还有什么? 我应该如何正确使用它们?

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

谢谢!

UPDATE:

提出的问题后,我做了一些简单的类加载器的测试。

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

这是我约
Difference between loadClass(String name) and loadClass(String name, boolean resolve)

+0

@Bohemian我已阅读的链接,我没有看到任何人强调说的Class.forName将初始化静态的东西还包括静态块和静态变量的区别。另外这两个方法实际上终于调用了不同的本地方法,private native void esolveClass0(Class c);私有静态本地Class forName0(字符串名称,布尔初始化,ClassLoader加载器)抛出ClassNotFoundException;它会导致差异吗? –

回答

9

考虑以下代码

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为false,则此时将不加载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)

A “类文本” 将返回类,没有初始化它

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(); 
+0

令人惊叹的答案。太糟糕了,这个问题被标记为重复。 –

1

ClassLoader.loadClass(字符串名称回答)将尝试使用speci加载类fied类加载器。 Class.forName(String name)将尝试使用默认系统类加载器层次结构加载该类。

相关问题