Class.forName()如何工作?

时间:2010-11-17 07:14:34

标签: java jdbc

我刚刚了解了java.sql package。它使用Class.forName()动态加载扩展DriverManager的驱动程序。 然后我们使用DriverManager.getConnection()方法获得连接。

那么整个过程如何运作? DriverManager类如何在不使用实际驱动程序的类名的情况下知道如何获取连接。

我们也可以将Class.forName()用于自定义应用程序......如果用一个例子来解释我会非常高兴。

4 个答案:

答案 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运算符创建类的实例时,它会做两件事

  1. 将类加载到内存中(如果未加载) - 这意味着从.class文件创建类的内存表示,以便可以从中创建实例。这包括初始化静态变量(解析该类)
  2. 创建该类的实例并存储对该变量的引用。
  3. 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自动发现驱动程序(如果足够新),因此调用是多余的,但出于习惯,许多人仍然使用它。