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

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

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


person Johanna    schedule 19.01.2010    source источник


Ответы (9)


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

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, вызов _ 2_ возвращает Class объект, связанный с классом или интерфейсом с заданным строковым именем, то есть возвращает test.Demo.class, на который влияет clazz переменная типа Class.

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

Таким образом, запуск этого класса Demo выводит следующий результат:

Hi!

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

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

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

РЕДАКТИРОВАТЬ (отвечая на вопрос OP, размещенного как комментарий): случай с драйверами 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 и доступен для создания связи.

  1. (...)

В обоих этих случаях ответственность за регистрацию нового загруженного класса 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.

person Pascal Thivent    schedule 19.01.2010
comment
но все еще на этом сайте: java.sun.com/docs/ книги / учебник / jdbc / basics / connected.html - person Johanna; 19.01.2010
comment
на указанном выше сайте написано, что: Вызов Class.forName автоматически создает экземпляр драйвера и регистрирует его в DriverManager, поэтому вам не нужно создавать экземпляр класса. Если бы вы создали свой собственный экземпляр, вы бы создали ненужный дубликат, но это не повредило бы. это означает, что с помощью Class.forName вы создадите экземпляр автоматически, и если вы хотите создать другой, он создаст ненужный экземпляр. Таким образом, как Calss.forName (), так и Class.forName (). newInstance () создадут экземпляр Водитель!! - person Johanna; 19.01.2010
comment
Драйверы JDBC особенные, они написаны со статическим блоком инициализации, где экземпляр создается и передается как параметр DriverManager.registerDriver. Вызов Class.forName в драйвере JDBC вызывает его инициализацию и, следовательно, выполнение статического блока. Взгляните на java2s.com/Open-Source/Java-Document/Database-DBMS/ в качестве примера. Так что это на самом деле частный случай из-за внутреннего устройства драйвера. - person Pascal Thivent; 19.01.2010
comment
Я заметил, что в другом ответе использование Class.newInstance () категорически не рекомендуется. Рекомендуется использовать Class.getConstructor (), а затем Constructor.newInstance () по очереди. Это позволяет избежать маскировки возможных исключений. - person Mr. Lance E Sloan; 27.03.2013
comment
newInstance позволяет создать экземпляр класса, о котором вы не знаете, пока время выполнения не сделало меня моим днем. Спасибо. - person Code Enthusiastic; 03.07.2013
comment
+1 за подробный ответ. Одно замечание: с JDBC 4.0 даже не нужно использовать Class.forName .... Механизм поставщика услуг Java SPM автоматически загружает драйвер базы данных. Нужно только указать jar-файл драйвера в пути к классам. См. stackoverflow.com/questions/26551648/ - person Chiseled; 25.10.2014

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

person Thomas Lötzer    schedule 19.01.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-адресу подключения во время _ 6_, который примерно выглядит следующим образом:

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() подальше.

person BalusC    schedule 19.01.2010

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

Class.forName("Somthing");

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

Class.forName("Somthing").newInstance();
person Hussain Akhtar Wahid 'Ghouri'    schedule 07.11.2013
comment
Отличный ответ! Понятно и лаконично! - person Gaurav; 17.10.2019

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

person Gopi    schedule 19.01.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());
person Arne Deutsch    schedule 19.01.2010

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

person sij    schedule 16.03.2011

Независимо от того, сколько раз вы вызываете метод Class.forName (), только после того, как статический блок выполняется, а не несколько раз:

package forNameMethodDemo;

public class MainClass {

    public static void main(String[] args) throws Exception {
        Class.forName("forNameMethodDemo.DemoClass");
        Class.forName("forNameMethodDemo.DemoClass");
        Class.forName("forNameMethodDemo.DemoClass");
        DemoClass demoClass = (DemoClass)Class.forName("forNameMethodDemo.DemoClass").newInstance();
    }
}


public class DemoClass {
    
    static {
        System.out.println("in Static block");
    }

    {
        System.out.println("in Instance block");
    }
}

вывод будет:

in Static block
in Instance block

Этот in Static block оператор печатается только один раз, а не трижды.

person Priyanka Wagh    schedule 20.02.2020

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

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

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

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

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

//args[0]=cmd line argument to give class at  runtime. 

Employee ob1=a.newInstance();

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

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

person Vinod Malkani    schedule 28.01.2016