2012-07-18 19 views
17

Hay 10 millones de artículos y documentos en que son los cargadores de clase de Java, y cómo/* por qué * para escribir el suyo ... pero todos parecen estar asumiendo algunas cosas que no puedo encontrar de manera simple ¡Respuesta para!¿Cuándo participan los cargadores de clase Java?

Entiendo el trabajo del cargador de clases: leer bytecode y construir un objeto a partir de él. Cargadores de clases diferentes hacen esto de manera diferente, etc.

Pero que nunca se le código contra una API cargador de clases en mi propio código, y nunca tener que escribir una de la mía, estoy teniendo enormes dificultades para entender cuando un ClassLoader ' el propio código de s realmente dispara.

Por ejemplo:

public static void main(String[] args) { 
    Fizz fizz = new Fizz(); 
    fuzz.buzz(); 
} 

aquí, tenemos un objeto Fizz. Antes de que se pueda crear una instancia de Fizz, necesitamos un cargador de clases para iniciar y cargar Fizz.class en su caché. ¿Dónde y cuándo sucede esto?!?! No está explícitamente en mi código, así que debe estar implícitamente en algún lugar del JRE ...?

tangencial a esa pregunta, si escribo mi propio cargador de clases, por ejemplo, WidgetClassLoader y desea configurarlo para cargar o bien todas las clases de mi aplicación, o tal vez sólo mi Fizz.class, ¿cómo puedo "ato" de este WidgetClassLoader en mi aplicación para que sabe qué cargador de clases usar? ¿Necesitaría mi código llamar explícitamente a este cargador de clases o sería implícito como el primer ejemplo? ¡Gracias por adelantado!

+0

Está en el JRE, por supuesto. Lea esto, y Google para la configuración del cargador de clases personalizado: http://www.javalobby.org/java/forums/t18345.html – duffymo

+0

@duffymo - vea mi comentario bajo la respuesta de Andre - ¡Tengo la misma pregunta para usted! – IAmYourFaja

+0

No veo la necesidad de escribir un cargador de clases propio. Ni una sola vez, en todo el tiempo que estuve escribiendo Java. Y eso es desde 1.0 en 1997. ¿Qué te hace pensar que lo necesitas? – duffymo

Respuesta

6

Tu pregunta no es tan trivial como crees ahora.

Su ejemplo de Fizz: ¿Cuándo está cargado Fizz? Esto se define en el JLS (Chapter 5.4: Linking). No define cuándo se carga Fizz, pero ofrece garantías sobre el comportamiento visible. Para la parte 'cuándo', si no se puede encontrar Fizz, se lanzará una excepción desde la primera declaración que acceda a Fizz (Fizz fizz = new Fizz()). Estoy bastante seguro de que será el nuevo Fizz() específicamente en este caso porque primero se evala el lado derecho de la expresión.En caso de que hubiera escrito así:

Fizz fizz = null; 
fizz = new Fizz(); 

En este caso, el fizz Fizz = null ya sería emitir la excepción, ya que su primer acceso a la clase Fizz.

¿Quién carga Fizz? Cuando se debe cargar una clase, el cargador de clases que 'pertenece' al código que requiere la clase se usa para obtener la clase. En el ejemplo de Fizz, este será el cargador de clases que cargó la clase con el método principal. Por supuesto, el cargador de clases puede elegir delegar en su cargador de clases padre si no puede cargar Fizz por sí mismo.

¿Cómo obtengo que la JVM use mi ClassLoader? Hay dos formas, explícita o implícitamente. Explícitamente: puedes cargar una clase a través de tu propio cargador de clases llamando a sus métodos. Implícitamente: cuando ejecutas código (es decir, métodos o inicializadores) de una clase que ya se cargó desde tu cargador de clases y una referencia de clase necesita resolverse en el proceso, tu cargador de clases se usará automáticamente porque es el cargador de clases que cargó el código en El primer lugar.

+0

Responde la parte de la que no estaba seguro, así que +1 de mí :-) –

+0

+1 no vale nada que "mi" ClassLoader es 'Thread.currentThread(). GetContextClassLoader()' es decir, cada subproceso tiene un cargador de clases predeterminado y ellos pueden ser diferentes –

+1

@Durandal, Acerca de la carga explícita e implícita, en el ejemplo de Fizz, es seguro que el cargador de clases personalizado no se usará ... ¿verdad? Básicamente, para la carga implícita, en algún lugar la carga explícita tiene que iniciar el proceso. Aquí puede usar Class.forName() para que la clase Fizz se cargue explícitamente o poner la clase Fizz en la ruta de la clase para que JVM la cargue. La conclusión es que el cargador de clases personalizado solo funcionará con un enfoque explícito, por primera vez. Corrígeme si estoy equivocado. – AKS

3

Java tiene un cargador de clases predeterminado. Esto busca declaraciones de clase en la ruta de clase predeterminada. Si escribe su propio cargador de clases, puede (y debería) configurar el cargador de clases padre. Este sería el valor predeterminado si no tiene otro. Si no lo haces, tu cargador de clases no podrá encontrar las clases API de Java. Si java busca una clase, no comienza a buscar con su cargador de clases personalizado, sino con el cargador de clases padre. Si este tiene un padre, comienza allí y así sucesivamente. Solo si no se pudo encontrar una clase, se utiliza el siguiente cargador de clases hijo para intentarlo de nuevo. De nuevo, esto continúa mientras haya niños. Si la clase no se encuentra en ninguno de los cargadores de la cadena, se arroja un ClassNotFoundException.

Por supuesto, java solo usa su cargador de clases si primero lo configura como cargador de clases predeterminado (llamando al Thread.currentThread().setContextClassLoader()) o carga la clase manualmente (llamando al loadClass()).

No estoy seguro de cuándo se invoca el cargador de clases. Creo que se invoca al iniciar el programa (en todas las clases declaradas como import) o al usar por primera vez una clase (declaración de la variable o llamada del constructor).

+0

Gracias @Andre, pero una vez más, esta es una respuesta a la pregunta "* ¿Cómo funcionan los cargadores de clases? *" Entiendo jerarquía del cargador de clases: lo que no entiendo es cuándo y dónde el cargador de clases predeterminado de JRE ejecuta el código que crea mi 'Fizz.class'. – IAmYourFaja

+0

Intenta establecer un punto de interrupción en 'java.lang.ClassLoader' en el método 'loadClass()'. –

+0

Lo he pensado un poco y he editado mi respuesta. Lo siento, pero no estoy seguro de esa última parte. –

0

La creación real de la clase se produce en defineClass. La clase se crea utilizando una matriz de bytes de cualquiera de varias fuentes.

El camino normal llegar a defineClass (que es protected) es a través de findClass (que, por supuesto, es también protected). Por lo tanto, el punto de entrada habitual es loadClass ->findClass ->defineClass. Pero hay otros caminos para casos especiales.

(Todo esto es bastante complicado, y representa una historia de la adición de capas como protección se hizo más complejo y los modos de acceso más variadas.)

0

Si usted está interesado en cargadores de clases y cuándo y cómo funcionan , también puede consultar the OSGi specification - me parece que será una lectura muy interesante para usted. OSGi es un marco para Java que proporciona modularidad, separación clara de códigos y administración del ciclo de vida y que es muy popular en este momento (por ejemplo, Eclipse se basa en uno).

OSGi usa cargadores de clases en gran medida y hay una muy buena explicación de cuándo y cómo ocurre todo con la carga de clases dentro de la especificación. Básicamente tienen un cargador de clases de paquete separado para cada paquete (así es como se llaman los módulos) y estos cargadores de clases se encargan de las dependencias y obtienen la clase correcta del otro paquete.

Cuestiones relacionadas