В чем разница между Class.forName()
и Class.forName().newInstance()
?
Я не понимаю существенной разницы (я кое-что прочитал о них!). Не могли бы вы помочь мне?
В чем разница между Class.forName()
и Class.forName().newInstance()
?
Я не понимаю существенной разницы (я кое-что прочитал о них!). Не могли бы вы помочь мне?
Возможно, пример, демонстрирующий, как используются оба метода, поможет вам лучше понять ситуацию. Итак, рассмотрим следующий класс:
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, контейнеры сервлетов - другие хорошие примеры: они используют динамическую загрузку во время загрузки и создают компоненты, которые они ничего не знают до выполнения.
Собственно, если вы хотите пойти дальше, посмотрите на статью Теда Ньюарда Понимание Class.forName(), которую я перефразировал в только что выше.
РЕДАКТИРОВАТЬ (отвечая на вопрос из OP, размещенный как комментарий): Случай драйверов JDBC немного особенный. Как описано в главе DriverManager Начало работы с API JDBC:
(...) Загружается класс
Driver
и поэтому автоматически регистрируется сDriverManager
, в одном из двух способы:
вызвав метод
Class.forName
. Это явно загружает класс водителя. Поскольку это не зависят от любой внешней настройки, таким образом загрузки драйвера рекомендуется один для использованияDriverManager
фреймворк. Следующая загрузка кода классacme.db.Driver
:Class.forName("acme.db.Driver");
Если
acme.db.Driver
написано так, что загрузка его вызывает экземпляр, который будет создан, а также вызовыDriverManager.registerDriver
с этим экземпляр как параметр (поскольку он должен делать), то он находится вDriverManager
список драйверов и доступный для создания соединения.(...)
В обоих случаях заново загруженный класс
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.
Класс .forName() предоставляет объект класса, который полезен для отражения. Методы, которые этот объект имеет, определяются Java, а не программистом, пишущим класс. Они одинаковы для каждого класса. Вызов newInstance() на этом дает вам экземпляр этого класса (т.е. Вызов Class.forName("ExampleClass").newInstance()
эквивалентен вызову new ExampleClass()
)), на который вы можете вызывать методы, которые определяет класс, доступ к видимым полям и т.д.
В мире JDBC обычная практика (согласно API JDBC) заключается в том, что вы используете 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()
прочь.
1: если вы заинтересованы только в статическом блоке класса, загрузите только класс и выполнили бы статические блоки, тогда все, что вам нужно, это:
Class.forName("Somthing");
2: если вы заинтересованы в загрузке класса, выполните его статические блоки и также хотите получить доступ к его нестационарной части, тогда вам понадобится экземпляр, а затем вам понадобится:
Class.forName("Somthing").newInstance();
Class.forName() получает ссылку на Class, Class.forName(). newInstance() пытается использовать конструктор no-arg для класса для возврата нового экземпляра.
"Class.forName()" возвращает тип класса для данного имени. "newInstance()" возвращает экземпляр этого класса.
В этом типе вы не можете напрямую вызвать какие-либо методы экземпляра, но можете использовать отражение для класса. Если вы хотите работать с объектом класса, вам нужно создать экземпляр его (так же, как вызвать "новый 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());
просто добавляя к выше ответам, когда у нас есть статический код (т.е. блок кода является независимым от экземпляра), который должен присутствовать в памяти, мы можем вернуть класс, чтобы мы использовали Class.forname( "someName" ) иначе, если у нас нет статического кода, мы можем пойти для Class.forname(). newInstance ( "someName" ), поскольку он загрузит блоки кода уровня объекта (не статические) в память
Class.forName() → forName() - это статический метод класса Class, он возвращает объект класса класса, используемый для отражения, а не объект класса пользователя, поэтому вы можете только называть его методами класса, такими как getMethods(), getConstructors ( ) и т.д.
Если вам нужен только запуск статического блока вашего класса (Runtime given) и получение информации о методах, конструкторах, модификаторах и т.д. вашего класса, которые вы можете сделать с этим объектом, который вы получите с помощью Class.forName()
Но если вы хотите получить доступ или вызвать метод класса (класс, который вы указали во время выполнения), то вам нужно иметь его объект, поэтому метод newInstance класса Class сделает это для вас. Создает новый экземпляр класса и возвращает это вам. Вам просто нужно набрать текст в свой класс.
ex-: предположим, что Employee - ваш класс, тогда
Класс a = класс .forName(args [0]);
//args [0] = cmd аргумент строки, чтобы дать класс во время выполнения.
Сотрудник ob1 = a.newInstance();
a.newInstance() похож на создание объекта с использованием нового Employee().
теперь вы можете получить доступ ко всем видимым полям и методам вашего класса.