AFAIK,java中提供了两种方法来从其名称初始化一个类.
类
public static Class forName(String 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));
Run Code Online (Sandbox Code Playgroud)
结果是
真的,真的,假的,真正的
UPDATE
这是我对loadClass(String name)和loadClass(String name,boolean resolve)之间差异的回答
irr*_*ble 10
考虑这段代码
class X
{
static{ System.out.println("init class X..."); }
int foo(){ return 1; }
Y bar(){ return new Y(); }
}
Run Code Online (Sandbox Code Playgroud)
最基本的API是 ClassLoader.loadClass(String name, boolean resolve)
Class classX = classLoader.loadClass("X", resolve);
Run Code Online (Sandbox Code Playgroud)
如果resolve为true,它还将尝试加载引用的所有类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");
Run Code Online (Sandbox Code Playgroud)
惯例是,JDBC驱动程序类在其静态初始化程序中注册自身.上面的代码将触发静态初始化,使驱动程序可供后续使用.
从今天的角度来看,这种设计真的很奇怪.我们通常不依赖静态初始化器.所以没有太多理由initialize=true,Class.forName(name)应该避免.
"class literal"将返回该类,而不会初始化它
Class c = com.mysql.jdbc.Driver.class;
// actually compiled to
Class c = Class.forName("com.mysql.jdbc.Driver", false, currentLoader);
Run Code Online (Sandbox Code Playgroud)
现在,"currentLoader"到底是什么?它是当前类的类加载器
class A
{
void foo()
{
currenLoader == THIS_A_CLASS.getClassLoader()
}
}
Run Code Online (Sandbox Code Playgroud)
当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();
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4769 次 |
| 最近记录: |