2012-03-18 4 views
13

Fue un error de mi compañero de trabajo: había un contenedor llamado test.jar y él ha corregido un error. Luego volvió a compilar el código y compiló un nuevo jar llamado testnew.jar El problema fue que puso estos dos jar en una carpeta que en classpath. Entonces, cuando el programa se estaba ejecutando, el comportamiento era una especie de desastre. No sabía lo que había pasado, pero después de eliminar test.jar, todo volvía a estar bien.Cómo funciona JVM cuando se incluyen dos jar iguales en classpath

Así que me pregunto cuál es el comportamiento de JVM. ¿Utiliza el archivo de clase en primer jar que cumple? ¿O algo mas?

Gracias.

Respuesta

4

Sí, de forma predeterminada utiliza clases del primer jar. Es por eso que debe verificar el directorio de la biblioteca para ver si hay duplicados. Pasamos tantas veces para mí y para mis colegas.

+0

Parece que no hay machanism para evitar esto. – XiaoYao

+1

Esta es una * suposición * interesante, pero ¿tiene alguna referencia para respaldarla? –

+0

@XiaoYao La forma de evitar esto es no agregar lo mismo dos veces. Si duplica lo mismo, tiene un comportamiento definido, por lo que no tiene por qué ser un problema. –

2

Si hay duplicados, se lee el que aparece primero en su classpath.

Editar Un archivo de ruta de clases, en general, se ve algo como esto ..

<classpath> 
     <classpathentry kind="lib" path="C:/Temp/test.jar"/> 
     <classpathentry kind="lib" path="C:/Temp/testnew.jar"/> 
    <classpathentry kind="output" path="build/classes"/> 
</classpath> 

Si su ruta de clase se ve algo como arriba, entonces la JVM se verá en test.jar en primer lugar, tal como aparece por primera vez en la ruta de clases Si quiere probarlo por su cuenta, intente mover el path de clase para testnew.jar sobre la entrada de test.jar. Verá que ahora se refiere a testnew.jar en lugar de a test.jar.

Referencia: FindingClasses

+0

¿Tiene una referencia para eso? –

+0

@ T.J.Crowder: bueno, no tengo una prueba escrita que diga eso, pero lo he probado por mi cuenta. Ese fue el comportamiento predeterminado que observé. Ver mi edición anterior, hice algo similar para probarlo. –

+0

'@ Shashank': Entonces * no puedes * confiar en el comportamiento, puede variar según el cargador de clases, o incluso dentro de los usos del mismo cargador de clases si usa alguna metodología de búsqueda extraña. Ver mi respuesta para más detalles. –

6

Por lo que yo puedo decir, que no está definido.

Java tiene un sistema de cargador de clases conectable, y por lo tanto la única manera de saber qué pasará es mirar la documentación del ClassLoader class, probablemente en particular el ClassLoader#findClass method, que no define un comportamiento para esto, y buscar en las secciones relevantes de JLS y JVM specs, ninguno de los cuales parece especificar una restricción en los cargadores de clase en este sentido. Por lo tanto, a menos que el cargador de clases que está utilizando su contenedor web documente el comportamiento, no puede saber con certeza qué clase se cargará.

Los probabilidades son que la primera que se encuentre que coincida con el nombre del binario de la clase será la carga, pero hay una gran diferencia entre el comportamiento que suponemos es el caso, y el comportamiento que se especifica y/o documentado.

+0

Encontré [esto] (http://docs.oracle.com/javase/1.4.2/docs/tooldocs/findingclasses.html) en los documentos de Java. Consulte la sección "Cómo el Java Launcher encuentra las clases JAR-class-path" .... Creo que dice que _Los archivos JAR que aparecen en la ruta JAR-class se buscan después de cualquier entrada de ruta de clase anterior, y antes de cualquier entrada que aparecen más adelante en la ruta de la clase ._...... así que ¿no crees que será el comportamiento predeterminado para buscar en la ruta de clases ??? .. –

+0

@ShashankKadne: buen trato, así que eso te dice qué La herramienta 'java' (el iniciador de Java) sí lo hace (al menos, lo que hizo en v1.4.2, ~ hace 10 años, pero dudo que haya cambiado). Lo cual es útil para cuando usas la herramienta 'java'. Por lo general, ** no ** le dice qué harán los cargadores de clases. El OP no dijo qué tipo de aplicación era (la aplicación de escritorio se inició a través de 'java', aplicación web donde el contenedor de clases está definido por el contenedor, etc.). –

1

JVM carga cualquier JAR específico en el classpath. Desde java 6 también ha habido una notación comodín. A continuación hay un par de ejemplos.

java -cp ".:lib/example.jar" Main 

Lo anterior solo cargará las clases que se encuentran en el directorio actual y en example.jar. Mientras que el siguiente ejemplo usará cualquier jar para cargar clases.

java -cp ".:lib/*" Main 

No creo que el fin para el cual el tarro en un directorio se examinó en primer lugar para encontrar una clase se define, simplemente, que cada vez que ordene al sistema operativo dio al enumerar los archivos.

Es probable que su IDE (o lo que sea que esté usando para ejecutar su programa) esté utilizando la última notación para ejecutar su programa.Podrías cambiarlo para que use el primero, aunque se romperá si alguna vez cambias el nombre de un frasco o añades otros nuevos.

Cuestiones relacionadas