2012-03-18 21 views
13

È stato un errore del mio collega: c'era un barattolo chiamato test.jar e lui ne ha risolto un bug. Quindi ricompila il codice e crea un nuovo jar chiamato testnew.jar Il problema è che ha messo questi due jar in una cartella che in classpath. Quindi, quando il programma era in esecuzione, il comportamento era una specie di caos. Non sapevo cosa fosse successo ma dopo aver rimosso test.jar, tutto andava bene di nuovo.Come JVM funziona quando due jar uguali sono inclusi nel classpath

Quindi mi chiedo quale sia il comportamento di JVM. Usa il file di classe nel primo contenitore che incontra? O qualcos'altro?

Grazie.

risposta

4

Sì, per impostazione predefinita utilizza le classi dal primo jar. Ecco perché è necessario controllare la directory della libreria per i duplicati. Succede tante volte per me e per i miei colleghi.

+0

Quindi sembra che non ci sia il machanism per evitare questo. – XiaoYao

+1

Questa è un'interessante * supposizione *, ma hai qualche riferimento per eseguirne il backup? –

+0

@XiaoYao Il modo per evitare questo è non aggiungere la stessa cosa due volte. Se duplichi la stessa cosa ha un comportamento definito quindi non deve essere un problema. –

2

Se ci sono duplicati, legge quello che appare per primo nel classpath.

Modifica Un file di percorso di classe, in generale, sembra qualcosa di simile ..

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

Se il percorso di classe sembra qualcosa di simile in precedenza, allora il vostro JVM esaminerà test.jar prima, come appare prima in il classpath. Se vuoi testarlo da solo, prova a spostare classpathentry per testnew.jar sopra la voce test.jar. Vedrai che ora fa riferimento a testnew.jar anziché a test.jar.

Riferimento: FindingClasses

+0

Avete un riferimento per questo? –

+0

@ T.J.Crowder: beh, non ho una prova scritta che lo dica, ma l'ho provato da solo. Questo è stato il comportamento predefinito che ho osservato. Vedere la mia modifica sopra, ho fatto qualcosa di simile a dimostrarlo. –

+0

'@ Shashank': Quindi non è possibile * fidarsi del comportamento, può variare a seconda del classloader o anche all'interno degli usi dello stesso classloader se utilizza una strana metodologia di ricerca. Vedi la mia risposta per i dettagli. –

6

Per quanto posso dire, non è definito.

Java ha un sistema di classloader pluggable, e quindi l'unico modo per sapere cosa accadrà è guardare la documentazione dello ClassLoader class, probabilmente in particolare lo ClassLoader#findClass method, che non definisce un comportamento per questo, e di guardare nelle corrispondenti sezioni di JLS e JVM specs, nessuno dei due sembra specificare un vincolo sui caricatori di classe a questo proposito. Pertanto, a meno che il comportamento non sia documentato dal caricatore di classi utilizzato dal contenitore Web, non è possibile sapere con certezza quale classe verrà caricata.

I probabilità sono che il primo trovato che corrisponde al nome binario della classe sarà quello caricato, ma c'è una grande differenza tra il comportamento supponiamo essere il caso, e il comportamento che è specificato e/o documentato.

+0

Ho trovato [questo] (http://docs.oracle.com/javase/1.4.2/docs/tooldocs/findingclasses.html) nei documenti java. Vedi la sezione "Come Java Launcher trova le classi del percorso di classe JAR" ... Penso che dice che _I file JAR che appaiono nel percorso della classe JAR vengono cercati dopo qualsiasi voce precedente del percorso di classe, e prima di qualsiasi voce che appaiono più avanti nel percorso della classe ._...... quindi non pensi che sarà il comportamento predefinito per esaminare il classpath ??? .. –

+0

@ShashankKadne: buon affare, così che ti dice cosa è il Lo strumento 'java' (il launcher Java) fa (almeno, quello che ha fatto in v1.4.2, ~ 10 anni fa, ma dubito che sia cambiato). Che è utile quando usi lo strumento 'java'. Non ** ti ** dirà, generalmente, cosa faranno i classloaders. L'OP non ha detto che tipo di applicazione era (l'applicazione desktop è stata avviata tramite 'java', l'applicazione Web in cui il programma di caricamento classi è definito dal contenitore, ecc.). –

1

JVM carica qualsiasi JAR specifico sul classpath. Da java 6 c'è stata anche una notazione jolly. Di seguito sono riportati un paio di esempi.

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

Quanto sopra carica solo le classi trovate nella directory corrente e all'interno di example.jar. Mentre il prossimo esempio userà qualsiasi jar per caricare classi da.

java -cp ".:lib/*" Main 

Non credo che l'ordine per il quale vaso in una directory viene esaminato prima di trovare una classe è definita, basta che mai ordinare il sistema operativo ha dato quando si elencano i file.

È probabile che il tuo IDE (o qualsiasi altra cosa tu stia utilizzando per eseguire il tuo programma) stia utilizzando quest'ultima notazione per eseguire il tuo programma.Puoi cambiarlo in modo che usi il primo, anche se si romperà se cambi mai il nome di un barattolo o ne aggiungi di nuovi.

Problemi correlati