我刚刚了解了java.sql package
。它使用Class.forName()
动态加载扩展DriverManager
的驱动程序。
然后我们使用DriverManager.getConnection()
方法获得连接。
那么整个过程如何运作? DriverManager类如何在不使用实际驱动程序的类名的情况下知道如何获取连接。
我们也可以将Class.forName()用于自定义应用程序......如果用一个例子来解释我会非常高兴。
答案 0 :(得分:62)
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
需要为特定连接字符串找到驱动程序时,它会依次调用每个已注册驱动程序上的acceptsURL
,直到有人说“是的,我可以成为该连接的驱动程序。”
请注意,这种注册驱动程序的方式相当老套 - 请查看DriverManager
的文档,了解更多现代获取数据源的方法。
答案 1 :(得分:16)
当我们使用new运算符创建类的实例时,它会做两件事
Class.forName
只做第一件事。
它将类加载到内存中,并将该引用作为Class的实例返回。如果我们想创建一个实例,那么我们可以调用该类的newInstance方法。这将调用默认构造函数(无参数构造函数)。
请注意,如果无法访问默认构造函数,则newInstance方法将抛出IllegalAccessException
。如果类是抽象类或接口,或者它没有默认构造函数,那么它将抛出InstantiationException
。如果在解析该类时有任何异常,则会抛出ExceptionInInitializerError
。
如果未定义默认构造函数,那么我们必须使用反射API调用defiend构造函数。
但Class.forName的主要优点是,它可以接受类名作为String参数。所以我们可以动态传递类名。但是如果我们使用new运算符创建类的实例,则无法动态更改类名。
Class.forName()
inturn将调用调用者ClassLoader的loadClass方法(调用Class.forName
的类的ClassLoder)。
默认情况下,Class.forName()
解析该类。这意味着,初始化该类中的所有静态变量。
可以使用Class.forName(String name,boolean initialize,ClassLoader loader)
使用Class.forName()
加载jdbc驱动程序的主要原因是,驱动程序可以动态更改。
在静态块中,所有驱动程序将创建自身的实例,并使用DriverManager.registerDriver()
方法使用DriverManager注册该类。由于Class.forName(String className)
默认解析该类,因此它将初始化静态初始值设定项。
所以当我们打电话给Class.forName("com.sun.jdbc.odbc.JdbcOdbcDriver")
时,
Driver类将被加载,实例化并向DriverManager注册
因此,如果您使用的是新操作员,则必须执行以下操作: 代码:
Driver drv = new com.sun.jdbc.odbc.JdbcOdbcDriver();
DriverManager.registerDriver(drv);
答案 2 :(得分:15)
Class.forName(..)
加载并初始化目标类。这反过来意味着调用静态初始化程序块(代码在static { .. }
中定义。
如果你看一下MySQL的驱动程序,那个静态块中的驱动程序正在注册:DriverManager.registerDriver(new Driver());
如果你能“承受”MySQL驱动程序的编译时依赖性,你可以省略Class.forName(..)
并自己注册驱动程序。
也就是说,使用Class.forName(..)
来初始化应用程序中的类很少是相关的,因为那里的编译时依赖性不是问题。
另请注意,从版本4开始,Class.forName(..)
is no longer required用于JDBC。通过使用service provider机制,您可以指示驱动程序管理器由系统属性加载什么。
答案 3 :(得分:4)
在SQL示例中经常提到Class.forName()
的原因是因为没有魔法告诉JDBC DriverManager 如何映射提供给真实驱动程序的JDBC URL。
E.g。 “mysql”应映射到给定的MySQL类,“瘦”映射到Oracle类,“as400”映射到DB2 / 400类。
通过显式加载类,这允许类中的代码注册自己与DriverManager一起运行。
现在魔术挂钩存在,允许JVM自动发现驱动程序(如果足够新),因此调用是多余的,但出于习惯,许多人仍然使用它。