简介
本文用示例介绍Java通过反射来实例化对象的方法。
Class.forName和ClassLoader的区别
关系
Class.forName()方法也是调用的 ClassLoader 来实现的。
区别
| 项 | Class.forName | ClassLoader |
| 灵活度 | 灵活度低。 例如:加载的类只能是classpath下的 | 灵活度高。 例如:可以自己编写加载类的方法:比如通过读取类文件的二进制数据,这个时候文件可以不在classpath中。 |
| 是否进行初始化 | 是。 forName方法最后调用 forName0(本地方法),第二个参数设置为了 true,代表对加载的类进行初始化(执行静态代码块、对静态变量赋值) | 否。 |
forName
@CallerSensitive
public static Class<?> forName(String className)
throws ClassNotFoundException {
Class<?> caller = Reflection.getCallerClass();
return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}
它有个重载(可以手动选择在加载类时是否要对其类进行初始化。)
public static Class<?> forName(String name, boolean initialize,
ClassLoader loader){}
实例(forName)
package org.example.a;
class Test {
static {
System.out.println("静态代码块");
}
public static final String title = getTitle();
private static String getTitle(){
System.out.println("执行getTitle()");
return "TITLE";
}
}
public class Demo {
public static void main(String[] args) {
Class<?> c = null;
try {
c = Class.forName("org.example.a.Test");
}catch (Exception e){
e.printStackTrace();
}
Test test = null;
try {
test = (Test) c.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
}
}
执行结果
静态代码块 执行getTitle()
实例(ClassLoader)
package org.example.a;
class Test {
static {
System.out.println("静态代码块");
}
public static final String title = getTitle();
private static String getTitle(){
System.out.println("执行getTitle()");
return "TITLE";
}
}
public class Demo {
public static void main(String[] args) {
Class<?> c = null;
try {
c = ClassLoader.getSystemClassLoader().loadClass("org.example.a.Test");
}catch (Exception e){
e.printStackTrace();
}
Test test = null;
try {
test = (Test) c.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
}
}
执行结果
无任何输出。
无参与有参构造
前边示例是无参构造,也可以有参构造:
package org.example.a;
import java.lang.reflect.Constructor;
class Test {
String name;
public Test(String name) {
this.name = name;
}
static {
System.out.println("静态代码块");
}
public static final String title = getTitle();
private static String getTitle(){
System.out.println("执行getTitle()");
return "TITLE";
}
}
public class Demo {
public static void main(String[] args) {
Class<?> c = null;
try {
c = Class.forName("org.example.a.Test");
}catch (Exception e){
e.printStackTrace();
}
Constructor<?> cons[] = c.getConstructors();
Test test = null;
try {
test = (Test) cons[0].newInstance("Tony");
} catch (Exception e) {
e.printStackTrace();
}
}
}
执行结果
静态代码块 执行getTitle()
JDBC为什么用Class.forName
JDBC 规范中明确要求 Driver(数据库驱动)类必须向 DriverManager 注册。
以 MySQL 的驱动为例,我们看到 Driver 注册到 DriverManager 中的操作写在了静态代码块中,这就是为什么在写 JDBC 时使用 Class.forName() 的原因了。
public class Driver extends NonRegisteringDriver implements java.sql.Driver {
//
// Register ourselves with the DriverManager
//
static {
try {
java.sql.DriverManager.registerDriver(new Driver());
} catch (SQLException E) {
throw new RuntimeException("Can't register driver!");
}
}
/**
* Construct a new driver and register it with DriverManager
*
* @throws SQLException
* if a database error occurs.
*/
public Driver() throws SQLException {
// Required for Class.forName().newInstance()
}
}

请先 !