Java Class.forName() 如何工作?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4202252/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 14:30:21  来源:igfitidea点击:

How does Class.forName() work?

javajdbc

提问by SonOfTheEARTh

I just learned about java.sql package. It uses Class.forName()to dynamically load the driver which extends DriverManager. Then we get connection using DriverManager.getConnection()method.

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

So how does the entire thing work?
How does DriverManager class know how to get the connection without using class name of the actual driver.

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

Also can we use Class.forName() for custom applications... if this is explained with an example I will be very happy.

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

采纳答案by Jon Skeet

Class.forNamesimply loads a class, including running its static initializers, like this:

Class.forName简单地加载一个类,包括运行它的静态初始化器,像这样:

class Foo {
    static {
        System.out.println("Foo initializing");
    }
}

public class Test {
    public static void main(String [] args) throws Exception {
        Class.forName("Foo");
    }
}

All the rest of the procedure you're talking about is JDBC-specific. The driver - which implements Driver, it doesn't extend DriverManager- simply registers an appropriate instance using DriverManager.registerDriver. Then when DriverManagerneeds to find a driver for a particular connection string, it calls connecton each registered driver in turn until one succeeds and returns a non-null connection.

您正在谈论的所有其余过程都是特定于 JDBC 的。驱动程序 - 它实现Driver,它不扩展DriverManager- 只是使用DriverManager.registerDriver. 然后当DriverManager需要为特定的连接字符串查找驱动程序时,它会connect依次调用每个注册的驱动程序,直到成功并返回一个非空连接。

Note that this way of registering drivers is reasonably old-fashioned - look at the docs for DriverManagerfor more modern ways of getting at a data source.

请注意,这种注册驱动程序的方式相当老式 - 查看文档以DriverManager了解获取数据源的更现代方式。

回答by Bozho

Class.forName(..)loads and initializes the target class. This in turn means that the static initializer blocks are invoked (code defined in static { .. }.

Class.forName(..)加载并初始化目标类。这反过来意味着静态初始化块被调用(代码定义在static { .. }.

If you look at, for example, MySQL's driver, in that static block the driver is registering itself: DriverManager.registerDriver(new Driver());

例如,如果您查看 MySQL 的驱动程序,在该静态块中,驱动程序正在自行注册: DriverManager.registerDriver(new Driver());

You can omit the Class.forName(..)and register the driver yourself if you can "afford" the compile-time dependency on MySQL's driver.

Class.forName(..)如果您可以“负担得起”对 MySQL 驱动程序的编译时依赖性,则可以省略并自行注册驱动程序。

That said, it will rarely be relevant to use Class.forName(..)to initialize classes from your application, because compile-time dependency is not an issue there.

也就是说,它很少与用于Class.forName(..)从您的应用程序初始化类相关,因为编译时依赖性在那里不是问题。

Also note that Class.forName(..)is no longer requiredfor JDBC since version 4. By using the service providermechanism you can instruct the driver manager what to load by a system property.

另请注意,自版本 4 起Class.forName(..)不再需要JDBC。通过使用服务提供者机制,您可以指示驱动程序管理器通过系统属性加载什么内容。

回答by Thorbj?rn Ravn Andersen

The reason why Class.forName()is frequently mentioned in SQL examples, is because there was no magic to tell the JDBC DriverManager howto map the JDBC URL provided to a real driver.

之所以Class.forName()在 SQL 示例中经常提到,是因为没有魔法告诉 JDBC DriverManager如何将提供的 JDBC URL 映射到真正的驱动程序。

E.g. "mysql" should map to a given MySQL class, "thin" maps to the Oracle class, "as400" maps to the DB2/400 class.

例如,“mysql”应该映射到给定的 MySQL 类,“thin”映射到 Oracle 类,“as400”映射到 DB2/400 类。

By explicitly loading the class, this allowed the code within the class registering itself with the DriverManager to be run.

通过显式加载类,这允许运行类中向 DriverManager 注册自身的代码。

These days the magic hooks are present allowing the JVM to autodiscover the drivers (if new enough) so the call is superfluous, but out of habit many still use it.

现在出现了魔术钩子,允许 JVM 自动发现驱动程序(如果足够新),因此调用是多余的,但出于习惯,许多人仍然使用它。

回答by Shubham Verma

When we create an instace of a class using new operator, it does two things

当我们使用 new 操作符创建一个类的实例时,它会做两件事

  1. Load the class in to memory, if it is not loaded - which means creating in-memory representation of the class from the .class file so that an instance can be created out of it. This includes initializing static variables (resolving of that class)
  2. create an instance of that class and store the reference to the variable.
  1. 将类加载到内存中,如果它没有加载——这意味着从 .class 文件创建类的内存表示,以便可以从中创建一个实例。这包括初始化静态变量(解析该类)
  2. 创建该类的实例并存储对变量的引用。

Class.forNamedoes only the first thing. It loads the class in to memory and return that reference as an instance of Class. If we want to create an instance then, we can call newInstance method of that class. which will invoke the default constructor (no argument constructor). Note that if the default constructor is not accessible, then newInstance method will throw an IllegalAccessException. and if the class is an abstract class or interface or it does not have a default constructor, then it will throw an InstantiationException. If any exception araises during resolving of that class, it will throw an ExceptionInInitializerError.

Class.forName只做第一件事。它将类加载到内存中并将该引用作为类的实例返回。如果我们想创建一个实例,我们可以调用该类的 newInstance 方法。这将调用默认构造函数(无参数构造函数)。请注意,如果默认构造函数不可访问,则 newInstance 方法将抛出一个IllegalAccessException. 如果该类是一个抽象类或接口,或者它没有默认构造函数,那么它将抛出一个InstantiationException. 如果在该类的解析过程中出现任何异常,它将抛出一个ExceptionInInitializerError.

If the default constructor is not defined, then we have to invoke the defiend constructor using reflection API.

如果未定义默认构造函数,则必须使用反射 API 调用 defiend 构造函数。

But the main advantage with Class.forName is, it can accept the class name as a String argument. So we can pass the class name dynamically. But if we create an instance of a class using new operator, the class name can't be changed dynamically.

但是 Class.forName 的主要优点是,它可以接受类名作为 String 参数。所以我们可以动态传递类名。但是如果我们使用 new 操作符创建一个类的实例,则不能动态更改类名。

Class.forName()inturn will call loadClass method of the caller ClassLoader (ClassLoder of the class from where Class.forNameis invoked).

Class.forName()反过来将调用调用者 ClassLoader 的 loadClass 方法(被调用的类的 ClassLoder Class.forName)。

By default, the Class.forName()resolve that class. which means, initialize all static variables inside that class. same can be changed using the overloaded method of Class.forName(String name,boolean initialize,ClassLoader loader)

默认情况下,Class.forName()解析该类。这意味着,初始化该类中的所有静态变量。同样可以使用重载的方法进行更改Class.forName(String name,boolean initialize,ClassLoader loader)

The main reason for loading jdbc driver using Class.forName()is, the driver can change dynamically. in the static block all Drivers will create an instance of itself and register that class with DriverManager using DriverManager.registerDriver()method. Since the Class.forName(String className)by default resolve the class, it will initialize the static initializer. So when we call Class.forName("com.sun.jdbc.odbc.JdbcOdbcDriver"), the Driver class will be loaded, instanciated and registers with DriverManager

使用加载jdbc驱动的主要原因Class.forName()是,驱动可以动态变化。在静态块中,所有驱动程序都将创建自己的一个实例,并使用DriverManager.registerDriver()方法向 DriverManager 注册该类。由于Class.forName(String className)默认解析类,它将初始化静态初始值设定项。因此,当我们调用时Class.forName("com.sun.jdbc.odbc.JdbcOdbcDriver"),Driver 类将被加载、实例化并注册到 DriverManager

So if you are using new Operator you have to do the following things.
Code:

因此,如果您使用的是 new Operator,则必须执行以下操作。
代码:

Driver drv = new com.sun.jdbc.odbc.JdbcOdbcDriver();
DriverManager.registerDriver(drv);