2010-04-15 13 views
11

Quando si chiama loadClass() su un ClassLoader, il ClassLoader controlla innanzitutto se la classe è stata caricata, o lo delega immediatamente al suo genitore ClassLoader?Modello di delega del ClassLoader Java?

API Java dice:

Quando ha chiesto di trovare una classe o una risorsa, un'istanza ClassLoader delegherà la ricerca per la classe o la risorsa alla sua classe genitore loader prima di tentare di trovare la classe o risorsa stessa.

Ma c'è un capitolo specifico sulla classe loader nel libro Java Reflection in azione che dice:

Classe loader chiama findLoadedClass per verificare se la classe è stata caricata already.If una class loader non trova una classe caricata, chiama loadClass nel caricatore della classe genitore.

Quale è corretto?

risposta

13

Un'implementazione corretta class loader volontà:

  1. Verificare se la classe è già stato caricato.
  2. In genere chiedere al caricatore classe padre di caricare la classe
  3. Tentativo di trovare la classe nel proprio percorso di classe.

L'implementazione predefinita di ClassLoader.loadClass è qualcosa di simile:

protected synchronized Class<?> loadClass(String name, boolean resolve) { 
    // First, check if this class loader has directly defined the class or if the 
    // JVM has initiated the class load with this class loader. 
    Class<?> result = findLoadedClass(name); 
    if (result == null) { 
    try { 
     // Next, delegate to the parent. 
     result = getParent().loadClass(name); 
    } catch (ClassNotFoundException ex) { 
     // Finally, search locally if the parent could not find the class. 
     result = findClass(ex); 
    } 
    } 
    // As a remnant of J2SE 1.0.2, link the class if a subclass of the class 
    // loader class requested it (the JVM never calls the method, 
    // loadClass(String) passes false, and the protected access modifier prevents 
    // callers from passing true). 
    if (resolve) { 
    resolveClass(result); 
    } 
    return result; 
} 

Alcune implementazioni di classe Loader delega ad altri caricatori di classe non-genitore (OSGi, ad esempio, i delegati ad un grafico di caricatori di classe a seconda del pacchetto) e alcune implementazioni del programma di caricamento classe cercheranno le classi in un classpath locale prima di delegare.

+0

Questo non è vero. Esistono molti modelli validi di caricamento delle classi come descritto su http://stackoverflow.com/a/245038/632951. Quello di cui parli come "corretto" è solo uno dei modelli. Gli altri modelli non sono in effetti implementati in questo modo. – Pacerier

+0

Hai ragione, la risposta era troppo prescrittiva. Ho aggiunto un linguaggio più flessibile e ho aggiunto esempi di scenari in cui un programma di caricamento classe potrebbe deviare. Grazie per il feedback. –

1

Questo è fondamentalmente come funziona. Si digita

Foo f = new Foo(); 

A questo punto il classloader determinerà se Foo() sono stati caricati cioè i bit in memoria/perm gen. Se è stato caricato, usalo. In caso contrario, delegarlo al caricatore della classe genitore per provare a risolvere la classe. I bit di questa classe vengono letti dal disco quindi caricati in memoria. Sul prossimo new Foo(), la classe verrebbe ora trovata in memoria/caricata.

2

L'API Java è corretta.

Quando richiesto di trovare una classe o risorsa, un'istanza ClassLoader sarà delegato la ricerca per la classe o risorsa alla sua classe genitore loader prima di tentare di trovare la classe o risorsa stessa.

Dal Java Classloading Mechanism -

Quando si carica una classe, una classe loader primi "delegati" la ricerca per la classe alla sua classe genitore loader prima di tentare di trovare la classe stessa.

+0

Sono confuso - questo significa che la risposta data da @bkail è errata? –

0

Per concordare con la risposta di Sri, verrà sempre delegata al genitore e l'api è corretta. Se stai giocando con il caricamento di classi, questo può rendere le cose un po 'difficili da ottenere o ottenere gli effetti che cerchi. Vorrei suggerire di avviare jvm con un classpath minimo e quindi caricare tutte le classi utilizzando il classloader personalizzato, il modo più semplice per farlo è usare uno URLClassloader o un oggetto composito che avvolge un URLClassloader in modo da essere in grado di tracciare quali classi sono caricate e quando.

Vale anche la pena tenere presente che una classe A caricata dal classloader C! = Classe A caricata dal classloader C se C e D non fanno parte della stessa gerarchia classloader-parent-child.

2

Le due affermazioni non si escludono esattamente a vicenda. La classe esisterà solo nell'insieme di classi caricate di ClassLoader se il genitore ClassLoader non ha ancora trovato la classe. Così,

Quando richiesto da trovare (il dato esterno che descrive) una classe o risorsa, un'istanza ClassLoader sarà delegato la ricerca (dati esterni che descrive) la classe o risorsa alla sua classe padre loader prima di tentare di trovare (i dati esterni che descrivono) la classe o la risorsa stessa.

Il che non le impedisce da corto circuito, se conosce il suo genitore non può trovare la classe, ma può (come mostrato da essa in precedenza il caricamento della classe)

0

C'è una questione più che dovrebbe essere notato in questo contesto. La documentazione delle API dice:

I metodi e costruttori di oggetti creati da una classe di caricamento può riferimento altre classi. Per determinare le classi a cui si fa riferimento, la macchina virtuale Java richiama il metodo loadClass del programma di caricamento classi che ha creato originariamente la classe .

Significato delle reti di classi di riferimento caricate dallo stesso programma di caricamento classi.

+0

Ciò non significherebbe: "la Java virtual machine richiama il metodo loadClass del programma di caricamento classi che ha originariamente creato la classe" - che verrà quindi delegato immediatamente al programma di caricamento classi genitore? –