Class.forName () vs ClassLoader.loadClass () – ¿cuál usar para la carga dinámica?

Al cargar dinámicamente una clase, ¿cuándo es apropiado usarla?

Class.forName("SomeClass"); 

y cuando debería usar

 ClassLoader.getSystemClassLoader().loadClass("SomeClass"); 

O, ¿son dos formas de hacer lo mismo?

¡Son bastante diferentes!

Como se indica en la documentación para Class.forName(String) ,

Devuelve el objeto Class asociado a la clase o interfaz con el nombre de cadena proporcionado. La invocación de este método es equivalente a: Class.forName(className, true, currentLoader)

( true aquí se refiere a ¿quieres inicializar la clase? )

Por otro lado, ClassLoader.loadClass(String) :

Invocar este método es equivalente a invocar loadClass(name, false) .

(aquí, el booleano no tiene nada que ver con la inicialización, pero si comprueba la documentación de loadClass (String, boolean), verá que todo lo que hace es cargar la clase, no inicializarla).

El primero ( Class.forName("SomeClass"); ) hará lo siguiente:

  • use el cargador de clases que cargó la clase que llama a este código
  • inicialice la clase (es decir, se ejecutarán todos los inicializadores estáticos)

El otro ( ClassLoader.getSystemClassLoader().loadClass("SomeClass"); ) hará lo siguiente:

  • use el cargador de clases “sistema” ( que es reemplazable )
  • no inicializar la clase (digamos, si la usa para cargar un controlador JDBC, no se registrará y no podrá usar JDBC).

Supongamos que está codificando una aplicación web que se ejecutará en un contenedor como Tomcat. Lo que hace Tomcat es crear un cargador de clases para cada aplicación web (para que pueda descargar las webapps más tarde y liberar memoria; ¡necesita un cargador de clases dedicado para que esto funcione!). En esta situación, ¡puede ver que ambas llamadas arrojarán resultados bastante diferentes!

Para obtener información más detallada (y autorizada) sobre la carga de clases y la inicialización, verifique las secciones 12.2 y 12.4 de la última (3ª) edición de la Especificación del lenguaje Java.

Class.forName() usa el cargador de clases del llamador e inicializa la clase (ejecuta intitializadores estáticos, etc.)

loadClass es un método de ClassLoader , por lo que utiliza un cargador explícitamente provisto e inicializa la clase de forma perezosa (en el primer uso).

Tenga en cuenta que hay un Class.forName () que también tiene un ClassLoader .

Básicamente están haciendo lo mismo. Sin embargo, el ClassLoader utilizado puede ser diferente. Class.forName usa el ClassLoader que obtienes de this.getClass (). GetClassLoader () mientras que tu otro código especifica usar el cargador de clases del sistema.

En la mayoría de las aplicaciones, este será el mismo cargador de clases, pero en entornos más complicados, como una aplicación J2EE o un applet, este puede no ser el caso.

ClassLoader es una clase abstracta, sin embargo, su aplicación siempre está cargada por un cargador de clases, podría haber cargadores de clases personalizados, como el cargador de clases de red o cualquier otra fuente.

Por otro lado, Class en sí mismo representa clases e interfaces y la clase Class tiene una función forName que usa el cargador de clases actual en el que su aplicación se ejecuta de forma predeterminada para cargar la clase.

Aquí está la fuente de Class.forName que, a su vez, invoca el cargador de clases llamante.

 public static Class forName(String className) throws ClassNotFoundException { return forName0(className, true, ClassLoader.getCallerClassLoader()); } 

http://docs.oracle.com/javase/1.4.2/docs/api/java/lang/ClassLoader.html

http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Class.html#forName(java.lang.String )

Sugerencia: cargador de clase Primordial http://docs.oracle.com/javase/1.4.2/docs/guide/security/spec/security-spec.doc5.html

  • Class.forName() carga e inicializa la clase. En el subsistema de cargador de clases, ejecuta las tres fases, es decir, carga, enlace e inicialización de fases.

  • Comportamiento ClassLoader.loadClass() , que retrasa la inicialización hasta que la clase se utiliza por primera vez. En el subsistema de carga de clases, ejecuta solo dos fases, es decir, carga y fases de enlace.

Por ejemplo:

 class MyClass { static { System.out.println("static block in MyClass"); } } public class TestCase1 { public static void main(String... args) throws Throwable { Class.forName("A"); } } //The above TestCase1 produce output: static block in MyClass public class TestCase2 { public static void main(String... args) throws Throwable { ClassLoader.getSystemClassLoader().loadClass("MyClass"); } } //The above TestCase2 not produce any output 

Amo la carga de clases en java …

Realmente depende de en qué contexto se esté ejecutando la aplicación. Obtendrá resultados diferentes si lo está utilizando desde un contexto web en lugar de solo un progtwig de línea de comando.

También he tenido problemas según el aspecto de ClassPath y lo que esperaba que sucediera.

Este artículo de JavaWorld explica una buena oferta al respecto.