Каково различие между “Class.forName ()” и “Class.forName () .newInstance ()”?

Между чем различие Class.forName() и Class.forName().newInstance()?

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

161
задан nbro 14 November 2016 в 13:53
поделиться

5 ответов

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

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

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

EDIT (отвечая на вопрос ОП, опубликованный в качестве комментария): Случай с драйверами JDBC немного особенный. Как объясняется в DriverManager главе Начало работы с JDBC API:

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

  1. вызовом метода Class.forName. Это явным образом загружает класс драйвера. Поскольку он не зависит от каких-либо внешних настроек, этот способ загрузки драйвера является рекомендуемым для использования DriverManager фреймворка. Следующий код загружает the class 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 Driver.

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

242
ответ дан 23 November 2019 в 21:25
поделиться

Class.forname () Получает ссылку на класс, Class.forname (). NewinStance () пытается использовать конструктор NO-ARG для класса для возврата нового экземпляра.

6
ответ дан 23 November 2019 в 21:25
поделиться

Class.Forname () дает вам объект класса, который полезен для размышлений. Методы, которые этот объект имеет определение Java, а не программистом, написанием класса. Они одинаковы для каждого класса. Вызов NewinStance () на это дает вам экземпляр этого класса (т.е. звонить Class.Forname («Экдамплекло»). NewinStance () Это эквивалентно вызову Новый экзамен () [) , на котором вы можете позвонить в методы, которые класс определяет, доступа к видимым полям и т. Д.

36
ответ дан 23 November 2019 в 21:25
поделиться

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

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

Пример для примера «Class.forname ()»

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

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());
3
ответ дан 23 November 2019 в 21:25
поделиться

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

package com.dbvendor.jdbc;

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

public class MyDriver implements Driver {

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

    public MyDriver() {
        //
    }

}

, вызывающий класс # 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 () .

29
ответ дан 23 November 2019 в 21:25
поделиться
Другие вопросы по тегам:

Похожие вопросы: