2010-01-30 15 views
7

Sono nuovo di java e sto ancora imparando. Ho avuto la mia testa intorno a classi interne e anonime. Ora ho una domanda tecnica su come si presenta java in memoria, quando si assegnano oggetti, si definiscono classi, ecc.Che aspetto ha Java in memoria

Come appare la memoria quando ho un campo che è un oggetto definito in una classe esterna vs una classe interiore. Le classi statiche hanno un aspetto diverso da quello non statico?

Ho solo bisogno di un riferimento visivo.

Grazie ragazzi

+0

Il "come" è un dettaglio di implementazione, non spec definito. Detto questo, questo libro non ti dice come effettivamente l'implementazione Java lo fa, ma ti dice come una VM simile a Java potrebbe farlo: http://www1.idc.ac.il/tecs/ – Dinah

risposta

3

i dettagli sono nella realizzazione (non le specifiche). Tuttavia, le implementazioni seguono generalmente un modello molto semplice. La maggior parte del layout della memoria in Java è molto semplice e diretta. La mia terminologia potrebbe non corrispondere alla terminologia Java, dal momento che non eseguo molta programmazione Java.

In generale, un oggetto inizia con un puntatore al suo vtable e quindi ha un gruppo di campi che seguono. I campi sono tipi primitivi (int/bool/float) o puntatori agli oggetti. Questo è tutto per gli oggetti. (Anche le classi sono oggetti.) I puntatori nulli sono come C, non sono validi, non come Python, dove Nessuno è un oggetto.

In una classe interna, è presente un campo nascosto aggiuntivo che punta a un'istanza della classe esterna. Questo è il modo in cui le classi interne accedono ai dati nella classe esterna. Le classi anonime funzionano allo stesso modo. I metodi statici sono solo metodi sulla classe anziché metodi sull'istanza.

Il vtable è dove avviene tutta la magia. Ogni classe ha il suo vtable condiviso tra tutti gli oggetti. Il vtable ha informazioni sulla classe come la dimensione delle sue istanze e come sono disposti i campi. Questa informazione è usata dal garbage collector. Il vtable ha anche un puntatore a tutti i metodi implementati dalla classe. Quando si chiama un metodo, il runtime estrae prima il puntatore vtable dall'oggetto, quindi estrae il puntatore del metodo dal vtable, quindi chiama il metodo e passa l'oggetto al metodo come parametro implicito. È simile al C++, ma molto più semplice da implementare. Il processo può essere saltato se il metodo o la classe è "finale".

So che Java non ha veramente "puntatori", ha "maniglie simboliche" o somesuch, ma le implementazioni comuni basta usare vecchie puntatori semplici.

1

Come quello che ha l'aspetto di memoria come quando ho ho un campo che è un oggetto che è definita in una classe al di fuori contro una classe interna . Le classi statiche sembrano diverse da quelle non statiche?

Un'istanza di classe interna (o anonima) non statica avrà un riferimento all'istanza di classe esterna che è stata utilizzata per istanziarla. Questo è ciò che consente a un metodo nella classe interna di fare riferimento ai membri a livello di istanza dichiarati nella classe che li include. Normalmente, questo riferimento viene passato alla classe interna come parametro extra nascosto nel costruttore. Ma se si usa reflection per creare un'istanza di classe interna, è necessario fornire esplicitamente tale parametro extra.

(Si noti che un diverso meccanismo viene utilizzato quando una classe anonima utilizza i locals/parametri nel campo di applicazione del metodo che crea un'istanza esso ...)

Se avete bisogno di maggiori dettagli, è possibile utilizzare per javap disassemblare i bytecode di alcune semplici classi di esempio.

Ho solo bisogno di un riferimento visivo.

Siamo spiacenti, non faccio belle immagini :-)

+0

ok ho trovato buona risorsa con diagrammi :) http://www.artima.com/insidejvm/ed2/jvm.html –

+0

+1 per non fare belle foto – stacker

+0

@pp - Ho guardato attraverso quella risorsa, e non ho potuto vedere nessuna immagini che hanno risposto a questa particolare domanda sulle classi interne. Potrebbe essere necessario acquistare una copia cartacea del libro ... –

3

Benvenuti nel mondo di Java. A differenza del linguaggio C in cui il linguaggio costruisce e la rappresentazione della memoria mappa quasi uno-a-uno, Java è leggermente più complicato.

Prima di tutto, quando le persone parlano di Java, potrebbe significare due cose: Java-the-language e Java-the-platform. Qui, intendo Java per essere il linguaggio di programmazione Java. Il codice scritto in Java viene prima compilato in bytecode, codice macchina per Java Virtual Machine. Se sei interessato ai dettagli della lingua Java, ecco lo The Java Language Specification. E per JVM, c'è The Java Virtual Machine Specification.

come si presenta la memoria quando ho un campo che è un oggetto definito in una classe esterna rispetto a una classe interna.

Interpreterò questo come si presenta il layout di memoria in Java Virtual Machine, dal momento che il layout fisico dipende dall'implementazione della JVM. Per questo ho scremato Structure of the Java Virtual Machine.

Come il linguaggio Java, la Java Virtual Machine opera su due generi di tipi: tipi primitivi e tipi di riferimento. Vi sono, corrispondentemente, due tipi di valori che possono essere memorizzati in variabili, passati come argomenti, restituiti dai metodi e operati su: valori primitivi e valori di riferimento.

La Java Virtual Machine si aspetta che quasi tutti i controlli di tipo avvengano in fase di compilazione, non dalla Java Virtual Machine stessa. In particolare, i dati non devono essere contrassegnati o altrimenti essere ispezionabili per determinare i tipi.

....

Un riferimento a un oggetto è considerato di avere Java Virtual Machine type reference. I valori di tipo reference possono essere pensati come puntatori agli oggetti.

Quindi la risposta sembra, è che entrambi i campi sarebbero esattamente identici: reference.

0

A statica (nidificato) classe funziona esattamente allo stesso modo di una classe di livello superiore. L'unica differenza è che il suo nome ha un altro nome di classe che lo precede. (Se guardi i file .class compilati vedrai che otterrai qualcosa come "Outer $ Nested.class" per una classe chiamata Nested nidificata in una classe chiamata Outer.)

Una classe interiore ha un campo nascosto che è un riferimento all'istanza contenente della sua classe esterna.Quando si scrive:

class Outer { 
    final int x; 

    class Nested { 
    int y; 

    Nested(int y) { 
     this.y = y; 
    } 

    int bar() { 
     return x + y; 
    } 
    } 

    void foo() { 
    Nested n = new Nested(5); 
    } 
} 

E 'come se si aveva scritto:

class Outer { 
    final int x; 

    static class Nested { 
    Outer outer; 
    int y; 

    Nested(Outer outer, int y) { 
     this.outer = outer; 
     this.y = y; 
    } 

    int bar() { 
     return outer.x + y; 
    } 
    } 

    void foo() { 
    Nested n = new Nested(this, 5); 
    } 
} 

Il nome di quel campo nascosto (che ho chiamato "esterno" qui) è nascosto a te, anche se puoi fare riferimento ad esso chiamando Outer.this all'interno della classe interna (dove Outer è il nome della tua classe esterna, ovviamente). Allo stesso modo, si noti che quando un metodo nella classe interna fa riferimento a qualcosa nella classe esterna, tale riferimento è in realtà tramite quel riferimento nascosto alla classe esterna.

Ci sono alcune complicazioni aggiuntive per quanto riguarda il modo in cui il controllo dell'accesso (ad esempio: privato) funziona con classi nidificate/interne, ma ciò non influenza in realtà la domanda "memoria" che stai chiedendo.

0
public class I { 
    class inner { 
     public void ctor() {}; 
    } 
} 

Aspetto dissasemmbled come, si potrebbe usare JAD

class I$inner { 

    // Field descriptor #6 LI; 
    final synthetic I this$0; 

    // Method descriptor #8 (LI;)V 
    // Stack: 2, Locals: 2 
    I$inner(I arg0); 
    0 aload_0 [this] 
    1 aload_1 
    2 putfield I$inner.this$0 : I [10] 
    5 aload_0 [this] 
    6 invokespecial java.lang.Object() [12] 
    9 return 
     Line numbers: 
     [pc: 0, line: 3] 
     Local variable table: 
     [pc: 0, pc: 10] local: this index: 0 type: I.inner 

    // Method descriptor #14()V 
    // Stack: 0, Locals: 1 
    public void ctor(); 
    0 return 
     Line numbers: 
     [pc: 0, line: 4] 
     Local variable table: 
     [pc: 0, pc: 1] local: this index: 0 type: I.inner 
} 

Come hexdump sarebbe iniziare con 0xcafebabe

Problemi correlati