Solución:
Quizás un ejemplo que demuestre cómo se utilizan ambos métodos le ayudará a comprender mejor las cosas. Entonces, considere la siguiente clase:
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();
}
}
Como se explica en su javadoc, llamando Class.forName(String)
devuelve el Class
objeto asociado con la clase o interfaz con el nombre de cadena dado es decir, vuelve test.Demo.class
que se ve afectado por clazz
variable de tipo Class
.
Entonces, llamando clazz.newInstance()
crea una nueva instancia de la clase representada por este Class
objeto. La clase es instanciada como por un new
expresión con una lista de argumentos vacía. En otras palabras, esto es realmente equivalente a un new Demo()
y devuelve una nueva instancia de Demo
.
Y ejecutando esto Demo
class por lo tanto imprime la siguiente salida:
Hi!
La gran diferencia con lo tradicional new
es eso newInstance
permite crear una instancia de una clase que no conoce hasta el tiempo de ejecución, lo que hace que su código sea más dinámico.
Un ejemplo típico es la API de JDBC que carga, en tiempo de ejecución, el controlador exacto necesario para realizar el trabajo. Los contenedores EJB, los contenedores Servlet son otros buenos ejemplos: utilizan la carga dinámica en tiempo de ejecución para cargar y crear componentes que no conocen nada antes del tiempo de ejecución.
En realidad, si desea ir más allá, eche un vistazo al artículo de Ted Neward Understanding Class.forName () que estaba parafraseando en el párrafo anterior.
EDITAR (respondiendo a una pregunta del OP publicada como comentario): El caso de los controladores JDBC es un poco especial. Como se explica en el capítulo DriverManager de Introducción a la API de JDBC:
(…) A
Driver
La clase se carga y, por lo tanto, se registra automáticamente con elDriverManager
, de una de estas dos formas:
llamando al método
Class.forName
. Esto carga explícitamente la clase de controlador. Dado que no depende de ninguna configuración externa, esta forma de cargar un controlador es la recomendada para usar elDriverManager
estructura. El siguiente código carga la claseacme.db.Driver
:Class.forName("acme.db.Driver");
Si
acme.db.Driver
se ha escrito para que cargarlo haga que se cree una instancia y también llame
DriverManager.registerDriver
con esa instancia como parámetro (como debería hacer), entonces está en el
DriverManager
lista de controladores y disponible para crear una conexión.(…)
En ambos casos, es responsabilidad del recién cargado
Driver
class para registrarse llamandoDriverManager.registerDriver
. Como se mencionó, esto debe hacerse automáticamente cuando se carga la clase.
Para registrarse durante la inicialización, el controlador JDBC normalmente usa un bloque de inicialización estático como este:
package acme.db;
public class Driver {
static {
java.sql.DriverManager.registerDriver(new Driver());
}
...
}
Vocación Class.forName("acme.db.Driver")
provoca la inicialización del acme.db.Driver
class y, por tanto, la ejecución del bloque de inicialización estático. Y Class.forName("acme.db.Driver")
de hecho “creará” una instancia, pero esto es solo una consecuencia de cómo se implementan (buenos) los controladores JDBC.
Como nota al margen, mencionaría que todo esto ya no es necesario con JDBC 4.0 (agregado como paquete predeterminado desde Java 7) y la nueva función de carga automática de los controladores JDBC 4.0. Consulte las mejoras de JDBC 4.0 en Java SE 6.
Class.forName () le da el objeto de clase, que es útil para la reflexión. Los métodos que tiene este objeto son definidos por Java, no por el programador que escribe la clase. Son los mismos para todas las clases. Llamar a newInstance () en eso le da una instancia de esa clase (es decir, llamar Class.forName("ExampleClass").newInstance()
es equivalente a llamar new ExampleClass()
), en el que puede llamar a los métodos que define la clase, acceder a los campos visibles, etc.
En el mundo JDBC, el normal práctica (según la API de JDBC) es que utilice Class#forName()
para cargar un controlador JDBC. El controlador JDBC debe registrarse a sí mismo en DriverManager
dentro de un bloque estático:
package com.dbvendor.jdbc;
import java.sql.Driver;
import java.sql.DriverManager;
public class MyDriver implements Driver {
static {
DriverManager.registerDriver(new MyDriver());
}
public MyDriver() {
//
}
}
Invocando Class#forName()
ejecutará todos los inicializadores estáticos. De esta manera el DriverManager
puede encontrar el controlador asociado entre los controladores registrados por URL de conexión durante getConnection()
que aproximadamente se parece a lo siguiente:
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");
}
Pero también hubo calesa Controladores JDBC, comenzando con el org.gjt.mm.mysql.Driver
como ejemplo bien conocido, que se registra incorrectamente dentro de la Constructor en lugar de un bloque estático:
package com.dbvendor.jdbc;
import java.sql.Driver;
import java.sql.DriverManager;
public class BadDriver implements Driver {
public BadDriver() {
DriverManager.registerDriver(this);
}
}
La única forma de hacer que funcione dinámicamente es llamar newInstance()
¡después! De lo contrario, se encontrará a primera vista con una inexplicable “SQLException: no hay un controlador adecuado”. Una vez más, esta es una insecto en el controlador JDBC, no en su propio código. Hoy en día, ningún controlador JDBC debería contener este error. Entonces puedes (y deberías) dejar el newInstance()
lejos.