简介
本文用示例介绍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() } }
请先
!