2011-12-01 18 views
38

Recientemente encontré un código que me hizo pensar. ¿Cuál es la diferencia entre:Java: Diferencia entre Class.forName y ClassLoader.loadClass

Class theClass = Class.forName("SomeImpl"); 
SomeImpl impl = (SomeImpl)theClass.newInstance(); 

y:

Class theClass = ClassLoader.loadClass("SomeImpl"); 
SomeImpl impl = (SomeImpl)theClass.newInstance(); 

¿Son sinónimo? ¿Es preferible uno al otro en ciertas circunstancias? ¿Qué hacer y qué no hacer con estos dos métodos?

Gracias de antemano.

+0

Personalmente trato de no utilizar cadenas literales en mi código ... Considere escribir 'SomeImpl.class.getSimpleName()' en lugar del literal codificado (ahorra dolores de cabeza al renombrar la clase). – Yuval

+8

@Yuval: ordinariamente estoy de acuerdo contigo, pero en el caso de 'Class.forName()' el * whole point * es que le pasas una cadena. Si tiene una instancia 'Clase ' rondando, entonces no necesita llamar 'Class.forName()'. Y si puede escribir 'SomeImpl.class' entonces puede escribir' new SomeImpl() 'en lugar de usar reflection en absoluto. –

+2

@Yuval, la carga dinámica de clases es una función central en Java y no tiene nada que ver con el uso de cadenas en lugar de clases. [RE. Pryden cubre eso ya] – bestsss

Respuesta

18

Class.forName() siempre usará el Cargador de clases de la persona que llama, mientras que ClassLoader.loadClass() puede especificar un ClassLoader diferente. Creo que Class.forName inicializa también la clase cargada, mientras que el enfoque ClassLoader.loadClass() no lo hace de inmediato (no se inicializa hasta que se usa por primera vez).

Acabo de encontrar este artículo cuando intento confirmar mi resumen del comportamiento de inicialización. Parece que este tiene la mayoría de la información que está buscando:

http://www.javaworld.com/javaworld/javaqa/2003-03/01-qa-0314-forname.html

Este uso está muy bien, aunque nunca he usado antes:

Class.forName(String, boolean, ClassLoader) 

que le permite especifique un ClassLoader y el parámetro boolean define si la clase debe inicializarse cuando está cargada o no.

+1

Solo usará el cargador de clases de la persona que llama si no proporciona uno. Del mismo artículo: "... Si elegir un cargador específico para cargar la clase es importante para su diseño, debe usar' ClassLoader.loadClass() '** o la versión de tres parámetros de forName() ** agregada en Java 2 Platform, Standard Edition (J2SE):' Class.forName (String, boolean, ClassLoader) '." – phs

10

respuesta de Shaun es más o menos correcta, salvo algunas omisiones/pequeños errores:

  • Class.forName asociados a la clase w/el cargador de clases (sin tener en cuenta si cualesquiera otras cargas a los padres de verdad), de ahí ClassLoader.findLoadedClass es exitosa próxima vez . Ese es un punto muy, muy importante, la mayoría de los cargadores de clases probarían Class c = findLoadedClass(name); if (c!=null) return c; como primeras declaraciones omitiendo la parte entera buscar/buscar. Llamar a ClassLoader.load directamente no agregará la clase a los cargados.

El caso tiene implicaciones cuando se carga a través de una estructura similar a la gráfica de ClassLoader, es decir, no se utiliza primero para buscar primero.

  • inicialización de la clase se realiza en loadClass del cargador de clases w/código así: if (resolve) resolveClass(c); y el cargador de clases realmente puede saltar resolverlo que se siente, pero no recomendada posible.

¿Qué hacer y qué no hacer con estos dos métodos?

A menos que tenga una idea muy clara de por qué quiere ClassLoader.loadClass(String), no lo use directamente. En cualquier otro caso, siempre confíe en Class.forName(name, true, classLoader).

En general la carga de clases está al lado de un arte y no puede ser cubierto en una respuesta simple (no es broma información sobre la pieza de arte)

3

Cuando utiliza utiliza Class.forName("SomeImpl"), que está obteniendo la clase a través del cargador de clases actual (es decir, el cargador de la clase a la que estás haciendo llamar el método).También será initialize la clase. En realidad es lo mismo que llamar al Class.forName("SomeImpl", true, currentLoader) donde currentLoader sería el cargador de clases de la persona que llama. Ver los detalles here.

El segundo método requiere que se elija primero un cargador de clases. No lo escriba como ClassLoader.loadClass("SomeImpl") ya que es no un método estático. Te necesita algo así como

final ClassLoader cl = this.getClass().getClassLoader(); 
Class theClass = cl.loadClass("SomeImpl"); 

Mente que subclases de cargador de clases deben reemplazar el método findClass en lugar de loadClass. Esto es lo mismo que llamar al método (protegido) loadClass("SomeImpl", false), donde el segundo argumento indica si se debe hacer o no el enlace.

Existen diferencias más sutiles ... El método loadClass espera un nombre de clase binaria según lo especificado por la especificación del lenguaje Java, mientras que forName también podrían utilizarse con cadenas que representan los tipos primitivos o clases de matriz.

En general, es mejor usar Class.forName, si es necesario, especificando un cargador de clases específico y si debe inicializarse o no, luego deje que la implementación descubra el resto. Usar cargadores de clases directamente es bueno para encontrar recursos en un jar o en el classpath.

1

Esta línea no se compilará:

Class theClass = ClassLoader.loadClass("SomeImpl"); 

porque loadClass no es un método estático de ClassLoader.

Para solucionar este problema, cree un objeto ClassLoader como sigue en una de las 3 formas posibles:

ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); 
ClassLoader classLoader = Main.class.getClassLoader();  // Assuming in class Main 
ClassLoader classLoader = getClass().getClassLoader();  // works in any class 

luego llamar:

Class theClass = classLoader.loadClass("SomeImpl"); 

-dbednar

0

El método loadClass() puede' se llamará como static. Cree una subclase para ClassLoader y tenga algunos otros métodos adicionales para realizar operaciones. Puede crear su propio cargador de clases extendiendo la clase ClassLoader. En funcional ambas formas son iguales.

Cuestiones relacionadas