Как работает Class.forName ()? - PullRequest
50 голосов
/ 17 ноября 2010

Я только что узнал о java.sql package.Он использует Class.forName() для динамической загрузки драйвера, который расширяет DriverManager.Затем мы получаем соединение, используя DriverManager.getConnection() метод.

Так как же все это работает?
Как класс DriverManager узнает, как получить соединение без использования имени класса фактического драйвера.

Также можем ли мы использовать Class.forName () для пользовательских приложений ... если это объясняется на примере, я буду очень рад.

Ответы [ 4 ]

63 голосов
/ 17 ноября 2010

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 необходимо найти драйвер для определенной строки подключения, он вызывает connect для каждого зарегистрированного драйвера по очереди, пока один из них не преуспеет и не вернет ненулевое соединение.

Обратите внимание, что этот способ регистрации драйверов довольно старомоден - посмотрите в документах DriverManager, чтобы узнать о более современных способах доступа к источнику данных.

19 голосов
/ 29 сентября 2016

Когда мы создаем класс с помощью оператора new, он делает две вещи

  1. Загрузить класс в память, если он не загружен - это означает создание представления класса в памяти из файла .class, чтобы из него можно было создать экземпляр. Это включает инициализацию статических переменных (разрешение этого класса)
  2. создать экземпляр этого класса и сохранить ссылку на переменную.

Class.forName делает только первое. Он загружает класс в память и возвращает эту ссылку как экземпляр класса. Если мы хотим создать экземпляр, мы можем вызвать метод newInstance этого класса. который вызовет конструктор по умолчанию (без аргумента конструктора). Обратите внимание, что если конструктор по умолчанию недоступен, метод newInstance выдаст IllegalAccessException. и если класс является абстрактным классом или интерфейсом или у него нет конструктора по умолчанию, тогда он выдаст InstantiationException. Если какое-либо исключение возникает во время разрешения этого класса, оно выдаст ExceptionInInitializerError.

Если конструктор по умолчанию не определен, то мы должны вызвать конструктор defiend, используя API отражения.

Но главное преимущество Class.forName заключается в том, что он может принимать имя класса в качестве аргумента String. Таким образом, мы можем передать имя класса динамически. Но если мы создаем экземпляр класса с помощью оператора new, имя класса нельзя изменить динамически.

Class.forName() inturn вызовет метод loadClass вызывающего ClassLoader (ClassLoder класса, из которого вызывается Class.forName).

По умолчанию Class.forName() разрешает этот класс. что означает, инициализировать все статические переменные внутри этого класса. то же самое можно изменить, используя перегруженный метод Class.forName(String name,boolean initialize,ClassLoader loader)

Основная причина загрузки драйвера jdbc с помощью Class.forName() заключается в том, что драйвер может динамически меняться. в статическом блоке все Драйверы создадут свой экземпляр и зарегистрируют этот класс в DriverManager, используя метод DriverManager.registerDriver(). Поскольку Class.forName(String className) по умолчанию разрешает класс, он инициализирует статический инициализатор. Поэтому, когда мы называем Class.forName("com.sun.jdbc.odbc.JdbcOdbcDriver"), класс Driver будет загружен, создан и зарегистрирован в DriverManager

Так что, если вы используете новый оператор, вы должны сделать следующее:
Код:

Driver drv = new com.sun.jdbc.odbc.JdbcOdbcDriver();
DriverManager.registerDriver(drv);
16 голосов
/ 17 ноября 2010

Class.forName(..) загружает и инициализирует целевой класс.Это, в свою очередь, означает, что статические блоки инициализатора вызываются (код, определенный в static { .. }.

Если вы посмотрите, например, драйвер MySQL, в этом статическом блоке драйвер регистрируется сам: DriverManager.registerDriver(new Driver());

Вы можете опустить Class.forName(..) и зарегистрировать драйвер самостоятельно, если вы можете «позволить» зависимость времени компиляции от драйвера MySQL.

Тем не менее, это редко будет иметь отношение к использованию Class.forName(..) чтобы инициализировать классы из вашего приложения, потому что здесь нет проблем с зависимостью во время компиляции.

Также обратите внимание, что Class.forName(..) больше не требуется для JDBC начиная с версии 4. Используя поставщик услуг механизм, который вы можете указать менеджеру драйверов, что загружать с помощью системного свойства.

4 голосов
/ 17 ноября 2010

Причина, по которой Class.forName() часто упоминается в примерах SQL, заключается в том, что не было никакого волшебства, чтобы сказать JDBC DriverManager , как сопоставить URL JDBC, предоставленный реальному драйверу.

Например, «mysql» должен отображаться на заданный класс MySQL, «thin» - на класс Oracle, «as400» - на класс DB2 / 400.

При явной загрузке класса это позволило использовать код внутрикласс регистрируется в DriverManager для запуска.

В наши дни присутствуют магические зацепки, позволяющие JVM автоматически обнаруживать драйверы (если они достаточно новые), поэтому вызов является излишним, но по привычке многие все еще используют его.,

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...