¿Cuál es la diferencia entre “Class.forName ()” y “Class.forName (). NewInstance ()”?

¿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?

Tal vez un ejemplo que demuestre cómo se usan ambos métodos te ayude a comprender mejor las cosas. Por lo tanto, 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, al llamar a Class.forName(String) devuelve el objeto Class asociado con la clase o interfaz con el nombre de cadena proporcionado, es decir, devuelve test.Demo.class que se ve afectado por la variable clazz de tipo Class .

Luego, al llamar a clazz.newInstance() crea una nueva instancia de la clase representada por este objeto de Class . La clase se instancia como si fuera una new expresión con una lista de argumentos vacía. En otras palabras, esto es aquí en realidad equivalente a una new Demo() y devuelve una nueva instancia de Demo .

Y al ejecutar esta clase de Demo , se imprime el siguiente resultado:

 Hi! 

La gran diferencia con el new newInstance es que newInstance permite instanciar una clase que no conoce hasta el tiempo de ejecución, haciendo que su código sea más dynamic.

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 en tiempo de ejecución para cargar y crear componentes que no conocen nada antes del tiempo de ejecución.

En realidad, si quiere 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 publicada como comentario): El caso de los controladores JDBC es un poco especial. Como se explica en el capítulo de DriverManager de Introducción a la API de JDBC :

(…) Se carga una clase Driver y, por lo tanto, se registra automáticamente con el DriverManager , de una de estas dos maneras:

  1. llamando al método Class.forName . Esto carga explícitamente la clase de controlador. Como no depende de ninguna configuración externa, esta forma de cargar un controlador es la recomendada para usar el marco DriverManager . El siguiente código carga la clase acme.db.Driver :

     Class.forName("acme.db.Driver"); 

    Si se ha escrito acme.db.Driver para que al cargarlo se cree una instancia y también se llame a DriverManager.registerDriver con esa instancia como parámetro (como debería ser), entonces está en la lista de controladores del DriverManager y disponible para crear una conexión.

  2. (…)

En ambos casos, es responsabilidad de la clase de Driver recientemente cargada registrarse por sí mismo llamando a DriverManager.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()); } ... } 

Llamar a Class.forName("acme.db.Driver") causa la inicialización de la clase acme.db.Driver y, por lo tanto, la ejecución del bloque de inicialización estático. Y Class.forName("acme.db.Driver") hecho “creará” una instancia, pero esto es solo una consecuencia de cómo se implementan los (buenos) controladores JDBC.

Como nota al margen, mencionaría que ya no se requiere todo esto 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. Vea las mejoras de JDBC 4.0 en Java SE 6 .

Class.forName () le proporciona el objeto de clase, que es útil para la reflexión. Los métodos que tiene este objeto están definidos por Java, no por el progtwigdor que escribe la clase. Son lo mismo para todas las clases. Llamar a newInstance () en eso le da una instancia de esa clase (es decir, llamar a Class.forName("ExampleClass").newInstance() es equivalente a llamar a new ExampleClass() ), en la que puede llamar a los métodos que la clase define , accede a los campos visibles, etc.

En el mundo de JDBC, la práctica habitual (según la API de JDBC) es que utilice la Class#forName() para cargar un controlador JDBC. El controlador JDBC debe registrarse 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() { // } } 

Invocar Class#forName() ejecutará todos los inicializadores estáticos . De esta forma, el DriverManager puede encontrar el controlador asociado entre los controladores registrados por la URL de conexión durante getConnection() que a grandes rasgos se verá de la siguiente manera:

 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 había controladores JDBC org.gjt.mm.mysql.Driver , comenzando con el ejemplo org.gjt.mm.mysql.Driver como bien conocido, que incorrectamente se registra dentro del 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 a newInstance() después! De lo contrario, se verá a primera vista inexplicable “SQLException: no hay un 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. Entonces puedes (y debes) dejar la newInstance() lejos.

1: si solo está interesado en el bloque estático de la clase, la carga de la clase solo lo haría, y ejecutaría bloques estáticos, entonces todo lo que necesita es:

 Class.forName("Somthing"); 

2: si está interesado en cargar la clase, ejecuta sus bloques estáticos y también desea acceder a su parte no estática, entonces necesita una instancia y luego necesita:

 Class.forName("Somthing").newInstance(); 

Class.forName () obtiene una referencia a una clase, Class.forName (). NewInstance () intenta usar el constructor no-arg para que la clase devuelva una nueva instancia.

“Class.forName ()” devuelve el tipo de clase para el nombre de stack. “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 el reflection de la clase. Si desea trabajar con un objeto de la clase, debe crear una instancia de la misma (lo mismo que llamar a “new MyClass ()”).

Ejemplo para “Class.forName ()”

 Class myClass = Class.forName("test.MyClass"); System.out.println("Number of public methods: " + myClass.getMethods().length); 

Ejemplo para “Class.forName (). NewInstance ()”

 MyClass myClass = (MyClass) Class.forName("test.MyClass").newInstance(); System.out.println("String representation of MyClass instance: " + myClass.toString()); 

simplemente agregando las respuestas anteriores, cuando tenemos un código estático (es decir, el bloque de código es independiente de la instancia) que necesita estar presente en la memoria, podemos hacer que devuelva la clase, así que usaremos Class.forname (“someName”) else si no tenemos código estático, podemos ir a Class.forname (). newInstance (“someName”) ya que cargará bloques de código de nivel de objeto (no estáticos) en la memoria

Class.forName () -> forName () es el método estático de Class class devuelve Class class object utilizado para reflexión no objeto de clase de usuario por lo que solo puede invocar métodos Class class en él como getMethods (), getConstructors () etc.

Si solo le interesa ejecutar un bloque estático de su clase (tiempo de ejecución) y solo obtener información de métodos, constructores, modificadores, etc. de su clase, puede hacer con este objeto que obtiene usando Class.forName ()

Pero si quiere acceder o llamar a su método de clase (clase que ha dado en tiempo de ejecución), entonces necesita tener su objeto tan nuevo. El método de instancia de la clase Class lo hace por usted. Crea una nueva instancia de la clase y se lo devuelve . Solo necesitas escribirlo en tu clase.

ex-: supongamos que el empleado es su clase, entonces

Clase a = Class.forName (args [0]);

// args [0] = cmd argumento de línea para dar clase en tiempo de ejecución.

Empleado ob1 = a.newInstance ();

a.newInstance () es similar a crear un objeto usando el nuevo Employee ().

ahora puede acceder a todos los campos y métodos visibles de su clase.