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?