Class.forName()如何工作?
我刚刚了解了java.sql package
。 它使用Class.forName()
来dynamic加载扩展DriverManager
的驱动程序。 然后我们使用DriverManager.getConnection()
方法获得连接。
那么整个事情是如何工作的呢?
如何DriverManager类知道如何获得连接,而不使用实际的驱动程序的类名称。
我们也可以使用Class.forName()为自定义应用程序…如果这是解释一个例子,我会很高兴。
Class.forName
只是加载一个类,包括运行它的静态初始值设定项,如下所示:
class Foo { static { System.out.println("Foo initializing"); } } public class Test { public static void main(String [] args) throws Exception { Class.forName("Foo"); } }
您所谈论的所有其他程序都是针对JDBC的。 驱动程序 – 实现Driver
,它不扩展DriverManager
– 只需使用DriverManager.registerDriver
注册适当的实例。 然后,当DriverManager
需要为特定连接string查找驱动程序时,它会acceptsURL
调用每个已注册的驱动程序的acceptsURL
,直到有人说“是的,我可以作为该连接的驱动程序”。
请注意,这种注册驱动程序的方式是相当老式的 – 查看DriverManager
的文档以获取更多的数据源的现代方法。
Class.forName(..)
加载并初始化目标类。 这又意味着调用静态初始化块(在static { .. }
定义的代码。
例如,如果您查看MySQL的驱动程序,那么在该静态块中,驱动程序正在注册自己: DriverManager.registerDriver(new Driver());
你可以省略Class.forName(..)
并注册驱动程序,如果你能“负担”MySQL驱动程序的编译时间依赖。
也就是说,使用Class.forName(..)
来初始化应用程序中的类是很less有用的,因为编译时间依赖并不是一个问题。
另请注意,从版本4开始,JDBC 不再需要 Class.forName(..)
通过使用服务提供者机制,您可以指示驱动程序pipe理器通过系统属性加载什么内容。
当我们使用new操作符创build一个类的实例时,它会做两件事
- 将类加载到内存中(如果未加载) – 这意味着从.class文件创build类的内存中表示,以便可以创build实例。 这包括初始化静态variables(解决该类)
- 创build该类的一个实例并存储对该variables的引用。
Class.forName
只做第一件事。 它将类加载到内存中,并将该引用作为Class的实例返回。 如果我们想创build一个实例,那么我们可以调用该类的newInstance方法。 这将调用默认的构造函数(无参数构造函数)。 请注意,如果默认构造函数不可访问,则newInstance方法将抛出IllegalAccessException
。 如果这个类是一个抽象类或接口,或者它没有默认的构造函数,那么它将抛出一个InstantiationException
。 如果在parsing该类时出现ExceptionInInitializerError
,则会抛出ExceptionInInitializerError
。
如果默认构造函数没有定义,那么我们必须使用reflectionAPI来调用defiend构造函数。
但是Class.forName的主要优点是,它可以接受类名作为String参数。 所以我们可以dynamic地传递类名。 但是,如果我们使用new运算符创build类的实例,则不能dynamic更改类名称。
Class.forName()
inturn将调用调用方ClassLoader的loadClass方法(调用Class.forName
的类的ClassLoder)。
默认情况下, Class.forName()
parsing该类。 这意味着,初始化该类中的所有静态variables。 同样可以使用Class.forName(String name,boolean initialize,ClassLoader loader)
的重载方法进行更改
使用Class.forName()
加载jdbc驱动程序的主要原因是,驱动程序可以dynamic更改。 在静态块中,所有的驱动程序将创build一个自己的实例,并使用DriverManager.registerDriver()
方法向DriverManager注册该类。 由于Class.forName(String className)
默认parsing类,它将初始化静态初始化器。 所以当我们调用Class.forName("com.sun.jdbc.odbc.JdbcOdbcDriver")
,Driver类将被加载,实例化并注册到DriverManager
所以如果你使用新的Operator,你必须做以下的事情。
码:
Driver drv = new com.sun.jdbc.odbc.JdbcOdbcDriver(); DriverManager.registerDriver(drv);
在SQL示例中经常提到Class.forName()
的原因是因为没有什么神奇的东西来告诉JDBC DriverManager 如何映射提供给真实驱动程序的JDBC URL。
例如“mysql”应该映射到给定的MySQL类,“thin”映射到Oracle类,“as400”映射到DB2 / 400类。
通过显式加载类,这允许运行在DriverManager中注册自己的类中的代码。
这些日子里存在的魔术挂钩允许JVM自动发现驱动程序(如果足够新的话),这样的调用是多余的,但出于习惯,许多人仍然使用它。