Ответы:
Возможно, пример, демонстрирующий использование обоих методов, поможет вам лучше понять вещи. Итак, рассмотрим следующий класс:
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
Затем вызов создает новый экземпляр класса, представленный этим объектом. Класс создается как бы выражением с пустым списком аргументов. Другими словами, это здесь фактически эквивалентно a и возвращает новый экземпляр .clazz.newInstance()
Class
new
new Demo()
Demo
И при запуске этого Demo
класса выводится следующий вывод:
Hi!
Большая разница с традиционным new
заключается в том, что он newInstance
позволяет создавать класс, который вы не знаете до времени выполнения, что делает ваш код более динамичным.
Типичным примером является API JDBC, который загружает во время выполнения точный драйвер, необходимый для выполнения работы. Контейнеры EJB, контейнеры сервлетов также являются хорошими примерами: они используют динамическую загрузку во время выполнения для загрузки и создания компонентов, о которых они ничего не знают до выполнения.
На самом деле, если вы хотите пойти дальше, взгляните на статью Теда Ньюарда «Понимание Class.forName ()», которую я перефразировал в параграфе чуть выше.
РЕДАКТИРОВАТЬ (отвечая на вопрос из ОП, опубликованных в качестве комментария): Случай с драйверами JDBC немного особенный. Как объяснено в главе DriverManager Начало работы с JDBC API :
(...)
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 .
DriverManager.registerDriver
. Вызов Class.forName
драйвера JDBC вызывает его инициализацию и, следовательно, выполнение статического блока. Посмотрите на java2s.com/Open-Source/Java-Document/Database-DBMS/… для примера. Так что это на самом деле частный случай из-за внутренних компонентов драйвера.
Class.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-Type для данного имени. «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 (), статический блок выполняется только один раз, а не несколько раз:
пакет для NameMethodDemo;
открытый класс 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();
}
}
открытый класс DemoClass {
static {
System.out.println("in Static block");
}
{
System.out.println("in Instance block");
}
}
вывод будет:
in Static block
in Instance block
Это in Static block
заявление печатается только один раз, а не три раза.
Class.forName () -> forName () - это статический метод класса Class, который возвращает объект класса Class, используемый для отражения, а не объект класса пользователя, поэтому вы можете вызывать только методы класса Class на нем, такие как getMethods (), getConstructors () и т. Д.
Если вы заботитесь только о запуске статического блока вашего (заданного во время выполнения) класса и только о получении информации о методах, конструкторах, модификаторах и т. Д. Вашего класса, вы можете делать с этим объектом, который вы получаете с помощью Class.forName ()
Но если вы хотите получить доступ к своему методу класса или вызвать его (класс, который вы указали во время выполнения), вам нужен его объект, чтобы метод newInstance класса Class сделал это для вас. Он создает новый экземпляр класса и возвращает его вам. . Вам просто нужно привести его к своему классу.
ex-: предположим, сотрудник тогда ваш класс
Class a = Class.forName (args [0]);
// args [0] = строковый аргумент cmd для предоставления класса во время выполнения.
Employee ob1 = a.newInstance ();
a.newInstance () аналогичен созданию объекта с использованием нового Employee ().
Теперь вы можете получить доступ ко всем видимым полям и методам вашего класса.