В чем разница между "Class.forName ()" и "Class.forName (). NewInstance ()"? - PullRequest
156 голосов
/ 19 января 2010

В чем разница между Class.forName() и Class.forName().newInstance()?

Я не понимаю существенной разницы (я что-то о них читал!). Не могли бы вы помочь мне?

Ответы [ 8 ]

235 голосов
/ 19 января 2010

Может быть, пример, демонстрирующий, как используются оба метода, поможет вам лучше понять вещи.Итак, рассмотрим следующий класс:

package test;

public class Demo {

    public Demo() {
        System.out.println("Hi!");
    }

    public static void main(String[] args) throws Exception {
        Class clazz = Class.forName("test.Demo");
        Demo demo = (Demo) clazz.newInstance();
    }
}

Как объяснено в его javadoc, вызов Class.forName(String) возвращает объект Class, связанный с классом или интерфейсом с даннымимя строки т.е. она возвращает test.Demo.class, которая зависит от переменной clazz типа Class.

Затем, вызов clazz.newInstance() создает новыйэкземпляр класса, представленный этим Class объектом.Класс создается как бы выражением new с пустым списком аргументов. Другими словами, здесь это фактически эквивалентно new Demo() и возвращает новый экземпляр Demo.

И запуск этого Demo класса выводит следующий вывод:

Hi!

Большая разница с традиционным new заключается в том, что newInstance позволяет создавать экземпляр класса, который вы не знаете до времени выполнения, делая ваш код более динамичным.

Типичным примером является JDBC API, который загружает во время выполнения точный драйвер, необходимый для выполнения работы.Контейнеры EJB, контейнеры сервлетов также являются хорошими примерами: они используют динамическую загрузку во время выполнения для загрузки и создания компонентов, о которых они ничего не знают до выполнения.

На самом деле, если вы хотите пойти дальше, взгляните на Теда.Бумага Ньюарда Понимание Class.forName () , которое я перефразировал в параграфе чуть выше.

РЕДАКТИРОВАТЬ (отвечая на вопрос ОП, опубликованный в виде комментария):Случай с драйверами JDBC немного особенный.Как объяснено в DriverManager главы Начало работы с JDBC API :

(...) Класс Driver загружен, и, следовательно,автоматически регистрируется с помощью DriverManager одним из двух способов:

  1. путем вызова метода Class.forName.Это явно загружает класс драйвера.Так как он не зависит от каких-либо внешних настроек, этот способ загрузки драйвера рекомендуется для использования DriverManager framework.Следующий код загружает класс acme.db.Driver:

    Class.forName("acme.db.Driver");
    

    Если acme.db.Driver был написан так, что загрузка вызывает создание экземпляра, а также вызывает DriverManager.registerDriver с этим экземпляром в качествепараметр (как и должно быть), затем он находится в списке драйверов DriverManager и доступен для создания соединения.

  2. (...)

В обоих этих случаях недавно загруженный класс Driver несет ответственность за регистрацию себя путем вызова DriverManager.registerDriver.Как уже упоминалось, это должно быть сделано автоматически при загрузке класса.

Чтобы зарегистрировать себя во время инициализации, драйвер JDBC обычно использует статический блок инициализации, например:

package acme.db;

public class Driver {

    static {
        java.sql.DriverManager.registerDriver(new Driver());
    }

    ...
}

Вызов Class.forName("acme.db.Driver") вызывает инициализацию класса acme.db.Driver и, таким образом,выполнение статического блока инициализации.И Class.forName("acme.db.Driver") действительно «создаст» экземпляр, но это всего лишь следствие того, как (хорошо) реализован драйвер JDBC.

В качестве примечания, я бы отметил, что все это больше не требуется приJDBC 4.0 (добавлен как пакет по умолчанию с Java 7) и новая функция автоматической загрузки драйверов JDBC 4.0.См. Усовершенствования JDBC 4.0 в Java SE 6 .

35 голосов
/ 19 января 2010

Class.forName () дает вам объект класса, который полезен для отражения.Методы этого объекта определены Java, а не программистом, пишущим класс.Они одинаковы для всех классов.Вызов newInstance () для этого дает вам экземпляр этого класса (то есть, вызывая Class.forName("ExampleClass").newInstance(), это эквивалентно вызову new ExampleClass()), для которого вы можете вызывать методы, которые определяет класс, получать доступ к видимым полям и т. Д.

28 голосов
/ 19 января 2010

В мире JDBC обычная практика (согласно JDBC API) заключается в том, что вы используете Class#forName() для загрузки драйвера JDBC. Драйвер JDBC должен зарегистрироваться в DriverManager внутри статического блока:

package com.dbvendor.jdbc;

import java.sql.Driver;
import java.sql.DriverManager;

public class MyDriver implements Driver {

    static {
        DriverManager.registerDriver(new MyDriver());
    }

    public MyDriver() {
        //
    }

}

Вызов Class#forName() выполнит все статические инициализаторы . Таким образом, DriverManager может найти связанный драйвер среди зарегистрированных драйверов по URL-адресу соединения во время getConnection(), что примерно выглядит следующим образом:

public static Connection getConnection(String url) throws SQLException {
    for (Driver driver : registeredDrivers) {
        if (driver.acceptsURL(url)) {
            return driver.connect(url);
        }
    }
    throw new SQLException("No suitable driver");
}

Но были и глючные драйверы JDBC, начиная с org.gjt.mm.mysql.Driver, как хорошо известный пример, который неправильно регистрируется внутри Конструктора вместо статического блока:

package com.dbvendor.jdbc;

import java.sql.Driver;
import java.sql.DriverManager;

public class BadDriver implements Driver {

    public BadDriver() {
        DriverManager.registerDriver(this);
    }

}

Единственный способ заставить его работать динамически - это позвонить newInstance() впоследствии! В противном случае вы столкнетесь с необъяснимым на первый взгляд «SQLException: нет подходящего водителя». Еще раз, это ошибка в драйвере JDBC, а не в вашем собственном коде. В настоящее время ни один драйвер JDBC не должен содержать эту ошибку. Таким образом, вы можете (и должны) оставить newInstance().

14 голосов
/ 07 ноября 2013

1: если вас интересует только статический блок класса, загрузка будет выполняться только классом, и он будет выполнять статические блоки, тогда все, что вам нужно:

Class.forName("Somthing");

2: если вы заинтересованы в загрузке класса, выполнении его статических блоков, а также хотите получить доступ к его не статической части, тогда вам нужен экземпляр, а затем вам нужно:

Class.forName("Somthing").newInstance();
6 голосов
/ 19 января 2010

Class.forName () получает ссылку на Class, Class.forName (). NewInstance () пытается использовать конструктор no-arg для Class, чтобы вернуть новый экземпляр.

3 голосов
/ 16 марта 2011

просто добавление к ответам выше, когда у нас есть статический код (т. Е. Блок кода не зависит от экземпляра), который должен присутствовать в памяти, мы можем вернуть класс, поэтому мы будем использовать Class.forname ("someName") иначе, если у нас нет статического кода, мы можем перейти к Class.forname (). newInstance ("someName"), поскольку он будет загружать блоки кода уровня объекта (не статические) в память

3 голосов
/ 19 января 2010

«Class.forName ()» возвращает тип класса для данного имени.«newInstance ()» возвращает экземпляр этого класса.

Для типа вы не можете напрямую вызывать методы экземпляра, но можете использовать только отражение для класса.Если вы хотите работать с объектом класса, вы должны создать его экземпляр (аналогично вызову «new MyClass ()»).

Пример для «Class.forName ()»

Class myClass = Class.forName("test.MyClass");
System.out.println("Number of public methods: " + myClass.getMethods().length);

Пример для "Class.forName (). NewInstance ()"

MyClass myClass = (MyClass) Class.forName("test.MyClass").newInstance();
System.out.println("String representation of MyClass instance: " + myClass.toString());
0 голосов
/ 28 января 2016

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

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

Но если вы хотите получить доступ или вызвать свой метод класса (класс, который вы указали во время выполнения), вам нужен его объект, поэтому метод newInstance класса Class сделает это за вас. Он создает новый экземпляр класса и возвращает это вам. Вам просто нужно привести его к типу.

ex-: предположим, сотрудник тогда ваш класс

Class a = Class.forName (args [0]);

// args [0] = строковый аргумент cmd для предоставления класса во время выполнения.

Сотрудник ob1 = a.newInstance ();

a.newInstance () аналогичен созданию объекта с использованием нового Employee ().

теперь вы можете получить доступ ко всем видимым полям и методам вашего класса.

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