¿Cuál es la diferencia entre Class.forName()
y Class.forName().newInstance()
?
No entiendo la diferencia significativa (¡he leído algo sobre ellos!). ¿Me podría ayudar?
Quizás un ejemplo que demuestre cómo se utilizan ambos métodos lo 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, llamar devuelve el objeto asociado con la clase o interfaz con el nombre de cadena dado, es decir, devuelve el que está afectado a la variable de tipo .Class.forName(String)
Class
test.Demo.class
clazz
Class
Luego, la llamada crea una nueva instancia de la clase representada por este objeto. La clase se instancia como si fuera una expresión con una lista de argumentos vacía. En otras palabras, esto es realmente equivalente a ay devuelve una nueva instancia de .clazz.newInstance()
Class
new
new Demo()
Demo
Y al ejecutar esta Demo
clase, se imprime el siguiente resultado:
Hi!
La gran diferencia con el tradicional new
es que 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 JDBC que carga, en tiempo de ejecución, el controlador exacto requerido para realizar el trabajo. Los contenedores EJB, los contenedores Servlet son otros buenos ejemplos: utilizan la carga dinámica de tiempo de ejecución para cargar y crear componentes que no saben 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 una pregunta del OP publicado 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 JDBC :
(...) Se
Driver
carga una clase y, por lo tanto, se registra automáticamente con elDriverManager
, de una de dos maneras:
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
marco. El siguiente código carga la claseacme.db.Driver
:Class.forName("acme.db.Driver");
Si
acme.db.Driver
se ha escrito de manera que al cargarlo, se crea una instancia y también se llamaDriverManager.registerDriver
con esa instancia como parámetro (como debería hacerlo), entonces está en laDriverManager
lista de controladores y está disponible para crear una conexión.(...)
En ambos casos, es responsabilidad de la
Driver
clase recién cargada registrarse a sí misma llamandoDriverManager.registerDriver
. Como se mencionó, esto debe hacerse automáticamente cuando se carga la clase.
Para registrarse durante la inicialización, el controlador JDBC generalmente usa un bloque de inicialización estático como este:
package acme.db;
public class Driver {
static {
java.sql.DriverManager.registerDriver(new Driver());
}
...
}
La llamada Class.forName("acme.db.Driver")
provoca la inicialización de la acme.db.Driver
clase y, por lo tanto, la ejecución del bloque de inicialización estática. Y de Class.forName("acme.db.Driver")
hecho "creará" una instancia, pero esto es solo una consecuencia de cómo se implementa (bueno) el controlador 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 característica de carga automática de los controladores JDBC 4.0. Consulte las mejoras de JDBC 4.0 en Java SE 6 .
DriverManager.registerDriver
. LlamarClass.forName
a un controlador JDBC provoca su inicialización y, por lo tanto, la ejecución del bloque estático. Eche un vistazo a java2s.com/Open-Source/Java-Document/Database-DBMS/… para ver un ejemplo. Así que este es realmente un caso particular debido a las partes internas del controlador.Class.forName () le proporciona el objeto de clase, que es útil para la reflexión. Los métodos que tiene este objeto los define Java, no el programador que escribe la clase. Son iguales para todas las clases. Llamar a newInstance () en eso le da una instancia de esa clase (es decir, llamarla
Class.forName("ExampleClass").newInstance()
es equivalente a llamarnew ExampleClass()
), en la que puede llamar a los métodos que define la clase, acceder a los campos visibles, etc.fuente
En el mundo JDBC, la práctica normal (de acuerdo con la API JDBC) es que se usa
Class#forName()
para cargar un controlador JDBC. El controlador JDBC debería registrarse enDriverManager
un bloque estático:La invocación
Class#forName()
ejecutará todos los inicializadores estáticos . De esta manera,DriverManager
puede encontrar el controlador asociado entre los controladores registrados por la URL de conexión durante lagetConnection()
cual se ve más o menos de la siguiente manera:Pero también había controladores JDBC con errores , comenzando con el
org.gjt.mm.mysql.Driver
ejemplo bien conocido, que se registra incorrectamente dentro del Constructor en lugar de un bloque estático:¡La única forma de hacerlo funcionar dinámicamente es llamar
newInstance()
después! De lo contrario, enfrentará a primera vista una "SQLException inexplicable: ningún controlador adecuado" Una vez más, este es un error en el controlador JDBC, no en su propio código. Hoy en día, ningún controlador JDBC debe contener este error. Así que puedes (y deberías) dejar denewInstance()
lado.fuente
1: si solo le interesa el bloque estático de la clase, la carga de la clase solo funcionaría y ejecutaría bloques estáticos, entonces todo lo que necesita es:
2: si está interesado en cargar la clase, ejecute sus bloques estáticos y también desea acceder a su parte no estática, entonces necesita una instancia y luego necesita:
fuente
Class.forName () obtiene una referencia a una clase, Class.forName (). NewInstance () intenta usar el constructor sin argumentos para que la clase devuelva una nueva instancia.
fuente
"Class.forName ()" devuelve el tipo de clase para el nombre dado. "newInstance ()" devuelve una instancia de esta clase.
En el tipo no puede llamar directamente a ningún método de instancia, pero solo puede usar la reflexión para la clase. Si desea trabajar con un objeto de la clase, debe crear una instancia (igual que llamar a "new MyClass ()").
Ejemplo para "Class.forName ()"
Ejemplo para "Class.forName (). NewInstance ()"
fuente
simplemente agregando a las respuestas anteriores, cuando tenemos un código estático (es decir, el bloque de código es independiente de la instancia) que debe estar presente en la memoria, podemos tener la clase devuelta, por lo que usaremos Class.forname ("someName") de lo contrario si no tiene código estático, podemos usar Class.forname (). newInstance ("someName") ya que cargará bloques de código de nivel de objeto (no estáticos) en la memoria
fuente
No importa cuántas veces llame al método Class.forName (), solo una vez que el bloque estático se ejecuta no varias veces:
clase pública MainClass {
}
clase pública DemoClass {
}
la salida será:
in Static block in Instance block
Esta
in Static block
declaración se imprime solo una vez, no tres veces.fuente
Class.forName () -> forName () es el método estático de la clase Class, devuelve el objeto Class class utilizado para la reflexión, no el objeto class del usuario, por lo que solo puede llamar a los métodos Class class como getMethods (), getConstructors () etc.
Si solo le interesa ejecutar un bloque estático de su clase (Tiempo de ejecución dado) y solo obtener información de métodos, constructores, Modificador, etc. de su clase, puede hacerlo con este objeto que obtiene usando Class.forName ()
Pero si desea acceder o llamar a su método de clase (clase que ha dado en tiempo de ejecución), entonces necesita tener su objeto para que el método newInstance de Class class lo haga por usted. Crea una nueva instancia de la clase y se la devuelve Solo necesitas escribirlo a tu clase.
ex-: supongamos que Empleado es su clase entonces
Clase a = Class.forName (args [0]);
// args [0] = argumento de línea cmd para dar clase en tiempo de ejecución.
Empleado ob1 = a.newInstance ();
a.newInstance () es similar a crear objetos usando new Employee ().
ahora puede acceder a todos los campos y métodos visibles de su clase.
fuente