В чем разница между 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, вызов _ 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
одним из двух способов:
вызвав метод
Class.forName
. Это явно загружает класс драйвера. Поскольку он не зависит от какой-либо внешней настройки, этот способ загрузки драйвера рекомендуется для использованияDriverManager
framework. Следующий код загружает класс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.
DriverManager.registerDriver
. Вызов Class.forName
в драйвере JDBC вызывает его инициализацию и, следовательно, выполнение статического блока. Взгляните на java2s.com/Open-Source/Java-Document/Database-DBMS/ в качестве примера. Так что это на самом деле частный случай из-за внутреннего устройства драйвера.
- person Pascal Thivent; 19.01.2010
Class.forName () дает вам объект класса, который полезен для отражения. Методы, которые имеет этот объект, определяются Java, а не программистом, пишущим класс. Они одинаковы для всех классов. Вызов newInstance () для этого дает вам экземпляр этого класса (т.е. вызов Class.forName("ExampleClass").newInstance()
эквивалентен вызову new ExampleClass()
), на котором вы можете вызывать методы, определенные классом, обращаться к видимым полям и т. Д.
В мире 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()
подальше.
1: если вас интересует только статический блок класса, будет выполняться загрузка только класса и будут выполняться статические блоки, тогда все, что вам нужно, это:
Class.forName("Somthing");
2: если вы заинтересованы в загрузке класса, выполнении его статических блоков, а также хотите получить доступ к его нестатической части, тогда вам понадобится экземпляр, а затем вам понадобятся:
Class.forName("Somthing").newInstance();
Class.forName () получает ссылку на Class, Class.forName (). NewInstance () пытается использовать конструктор без аргументов для Class, чтобы вернуть новый экземпляр.
«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());
просто добавляя к приведенным выше ответам, когда у нас есть статический код (т.е. блок кода не зависит от экземпляра), который должен присутствовать в памяти, мы можем вернуть класс, поэтому мы будем использовать Class.forname ("someName"), иначе, если мы нет статического кода, мы можем использовать Class.forname (). newInstance ("someName"), поскольку он загружает блоки кода уровня объекта (нестатические) в память
Независимо от того, сколько раз вы вызываете метод 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
оператор печатается только один раз, а не трижды.
_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()
.
теперь вы можете получить доступ ко всем видимым полям и методам вашего класса.